精华内容
下载资源
问答
  • C++线程同步实例分析

    2020-09-04 03:17:32
    主要介绍了C++线程同步实例分析,以实例的形式较为深入的分析了C++的线程同步问题,是一个较为经典的线程同步问题,需要的朋友可以参考下
  • 主要介绍了C++ 线程(串行 并行 同步 异步)详解的相关资料,需要的朋友可以参考下
  • C++线程同步的四种方式(Windows)

    万次阅读 多人点赞 2017-07-03 23:20:56
    为什么要进行线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的...

    一、为什么要进行线程同步?

    在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。

    两个线程同时对一个全局变量进行加操作,演示了多线程资源访问冲突的情况。代码如下:

    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    int number = 1;
    
    unsigned long __stdcall ThreadProc1(void* lp) {
    	while (number < 100) {
    		cout << "thread 1 :"<<number << endl;
    		++number;
    		_sleep(100);
    	}
    
    	return 0;
    }
    
    unsigned long __stdcall ThreadProc2(void* lp) {
    	while (number < 100) {
    		cout << "thread 2 :"<<number << endl;
    		++number;
    		_sleep(100);
    	}
    
    	return 0;
    }
    
    int main() {
    	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    	CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    
    	Sleep(10*1000);
    
    	system("pause");
        return 0;
    }
    

    运行结果:
    这里写图片描述
    可以看到有时两个线程计算的值相同,不是我们想要的结果。

    二、关于线程同步

    线程之间通信的两个基本问题是互斥和同步。

    • 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
    • 线程互斥是指对于共享的操作系统资源(指的是广义的”资源”,而不是Windows的.res文件,譬如全局变量就是一种共享资源),在各线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。

    线程互斥是一种特殊的线程同步。实际上,互斥和同步对应着线程间通信发生的两种情况:

    • 当有多个线程访问共享资源而不使资源被破坏时;
    • 当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。

    从大的方面讲,线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。

    • 用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快,适合于对线程运行速度有严格要求的场合。
    • 内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象,使用时必须将线程从用户模式切换到内核模式,而这种转换一般要耗费近千个CPU周期,因此同步速度较慢,但在适用性上却要远优于用户模式的线程同步方式。

    在WIN32中(区别于Linux,其实也差不多),同步机制主要有以下几种:
    (1)事件(Event);
    (2)信号量(semaphore);
    (3)互斥量(mutex);
    (4)临界区(Critical section)。

    三、Win32中的四种同步方式

    【1】临界区

    临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

    临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()LeaveCriticalSection()函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。代码如下:

    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    int number = 1;	//定义全局变量
    CRITICAL_SECTION Critical;		//定义临界区句柄
    
    unsigned long __stdcall ThreadProc1(void* lp) {
    	while (number < 100) {
    		EnterCriticalSection(&Critical);
    		cout << "thread 1 :"<<number << endl;
    		++number;
    		_sleep(100);
    		LeaveCriticalSection(&Critical);
    	}
    
    	return 0;
    }
    
    unsigned long __stdcall ThreadProc2(void* lp) {
    	while (number < 100) {
    		EnterCriticalSection(&Critical);
    		cout << "thread 2 :"<<number << endl;
    		++number;
    		_sleep(100);
    		LeaveCriticalSection(&Critical);
    	}
    
    	return 0;
    }
    
    int main() {
    	InitializeCriticalSection(&Critical);	//初始化临界区对象
    	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    	CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    
    	Sleep(10*1000);
    	system("pause");
        return 0;
    }
    

    运行结果:
    这里写图片描述
    可以看到,也实现了有序输出,实现了线程同步。

    【2】事件

    事件(Event)是WIN32提供的最灵活的线程间同步方式,事件可以处于激发状态(signaled or true)或未激发状态(unsignal or false)。根据状态变迁方式的不同,事件可分为两类:
    (1)手动设置:这种对象只可能用程序手动设置,在需要该事件或者事件发生时,采用SetEventResetEvent来进行设置。
    (2)自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。

    使用”事件”机制应注意以下事项:
    (1)如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空间中的其它全局命名对象冲突;
    (2)事件是否要自动恢复;
    (3)事件的初始状态设置。

    由于event对象属于内核对象,故进程B可以调用OpenEvent函数通过对象的名字获得进程A中event对象的句柄,然后将这个句柄用于ResetEventSetEventWaitForMultipleObjects等函数中。此法可以实现一个进程的线程控制另一进程中线程的运行,例如:

    HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, true, "MyEvent"); 
    ResetEvent(hEvent);
    

    代码示例:

    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    int number = 1;	//定义全局变量
    HANDLE hEvent;	//定义事件句柄
    
    unsigned long __stdcall ThreadProc1(void* lp) {
    	while (number < 100) {
    		WaitForSingleObject(hEvent, INFINITE);	//等待对象为有信号状态
    		cout << "thread 1 :"<<number << endl;
    		++number;
    		_sleep(100);
    		SetEvent(hEvent);
    	}
    
    	return 0;
    }
    
    unsigned long __stdcall ThreadProc2(void* lp) {
    	while (number < 100) {
    		WaitForSingleObject(hEvent, INFINITE);	//等待对象为有信号状态
    		cout << "thread 2 :"<<number << endl;
    		++number;
    		_sleep(100);
    		SetEvent(hEvent);
    	}
    
    	return 0;
    }
    
    int main() {
    	hEvent = CreateEvent(NULL, FALSE, TRUE, "event");
    	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    	CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    
    	Sleep(10*1000);
    	system("pause");
        return 0;
    }
    

    运行结果:
    这里写图片描述
    可以看到,实现了有序输出,实现了线程同步。

    【3】信号量

    信号量是维护0到指定最大值之间的同步对象。信号量状态在其计数大于0时是有信号的,而其计数是0时是无信号的。信号量对象在控制上可以支持有限数量共享资源的访问。

    信号量的特点和用途可用下列几句话定义:
    (1)如果当前资源的数量大于0,则信号量有效;
    (2)如果当前资源数量是0,则信号量无效;
    (3)系统决不允许当前资源的数量为负值;
    (4)当前资源数量决不能大于最大资源数量。

    创建信号量

    函数原型为:

     HANDLE CreateSemaphore (
       PSECURITY_ATTRIBUTE psa, //信号量的安全属性
       LONG lInitialCount, //开始时可供使用的资源数
       LONG lMaximumCount, //最大资源数
       PCTSTR pszName);     //信号量的名称
    

    释放信号量

    通过调用ReleaseSemaphore函数,线程就能够对信标的当前资源数量进行递增,该函数原型为:

    BOOL WINAPI ReleaseSemaphore(
       HANDLE hSemaphore,   //要增加的信号量句柄
       LONG lReleaseCount, //信号量的当前资源数增加lReleaseCount
       LPLONG lpPreviousCount  //增加前的数值返回
       );
    

    打开信号量

    和其他核心对象一样,信号量也可以通过名字跨进程访问,打开信号量的API为:

     HANDLE OpenSemaphore (
       DWORD fdwAccess,      //access
       BOOL bInherithandle,  //如果允许子进程继承句柄,则设为TRUE
       PCTSTR pszName  //指定要打开的对象的名字
      );
    

    代码示例:

    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    int number = 1;	//定义全局变量
    HANDLE hSemaphore;	//定义信号量句柄
    
    unsigned long __stdcall ThreadProc1(void* lp) {
    	long count;
    	while (number < 100) {
    		WaitForSingleObject(hSemaphore, INFINITE);	//等待信号量为有信号状态
    		cout << "thread 1 :"<<number << endl;
    		++number;
    		_sleep(100);
    		ReleaseSemaphore(hSemaphore, 1, &count);
    	}
    
    	return 0;
    }
    
    unsigned long __stdcall ThreadProc2(void* lp) {
    	long count;
    	while (number < 100) {
    		WaitForSingleObject(hSemaphore, INFINITE);	//等待信号量为有信号状态
    		cout << "thread 2 :"<<number << endl;
    		++number;
    		_sleep(100);
    		ReleaseSemaphore(hSemaphore, 1, &count);
    	}
    
    	return 0;
    }
    
    int main() {
    	hSemaphore = CreateSemaphore(NULL, 1, 100, "sema");
    	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    	CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    
    	Sleep(10*1000);
    	system("pause");
        return 0;
    }
    

    运行结果:
    这里写图片描述
    可以看到,实现了有序输出,实现了线程间同步。

    【4】互斥量

    采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。

    代码示例:

    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    int number = 1;	//定义全局变量
    HANDLE hMutex;	//定义互斥对象句柄
    
    unsigned long __stdcall ThreadProc1(void* lp) {
    	while (number < 100) {
    		WaitForSingleObject(hMutex, INFINITE);
    		cout << "thread 1 :"<<number << endl;
    		++number;
    		_sleep(100);
    		ReleaseMutex(hMutex);
    	}
    
    	return 0;
    }
    
    unsigned long __stdcall ThreadProc2(void* lp) {
    	while (number < 100) {
    		WaitForSingleObject(hMutex, INFINITE);
    		cout << "thread 2 :"<<number << endl;
    		++number;
    		_sleep(100);
    		ReleaseMutex(hMutex);
    	}
    
    	return 0;
    }
    
    int main() {
    	hMutex = CreateMutex(NULL, false, "mutex");		//创建互斥对象
    	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    	CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    
    	Sleep(10*1000);
    	system("pause");
        return 0;
    }
    

    运行结果:
    这里写图片描述
    可以看到,实现了有序输出,实现了线程同步。

    最后,搜索并关注微信公众号:让我思考一下!获得更多内容。

    展开全文
  • c++ 线程同步机制

    千次阅读 2017-03-01 16:23:25
    c++线程同步

    互斥量

    在使用互斥量的时候,最好使用RAII进行封装,使用非递归的互斥量,尽量在一个函数内进行lock、unlock。

    常有的互斥量对象,简单的互斥对象std::mutex,带有超时机制的互斥对象std::timed_mutex,一般使用RAII来避免死锁的情况。

    std::lock_guard,对象生存期内是不允许手动加锁解锁的。构造时可选是否加锁(不加锁时假定当前线程已经获得锁的所有权),析构时自动释放锁,所有权不可转移。

    std::unique_lock,对象生存期可以进行手动加锁解锁。比lock_guard更加灵活。


    lock_guard只支持std::lock和std::adopt_lock。

    unique_lock则支持:std:lock、std::defer_lock、std::try_lock、std::adopt_lock。

    defer_lock 不取得互斥量的所有权;当多个线程都使用同样N个互斥量的时候,必须保证其加锁的顺序是一致的这种情况下使用try_lock更好。

    try_lock 则会在没有阻塞的时候取得互斥量的所有权;其变种try_lock_for(duration)和try_lock_until(timepoint)。

    adopt_lock  即使互斥量已经被另外的线程加锁,也会夺取互斥量的所有权进而在该线程加锁。



    条件变量

    条件变量是一个或多个线程等待某个布尔表达式为真,即等待别的线程“唤醒”它。

    对于wait()端,为了防止虚假唤醒,必须配合锁一起使用:

    1. 必须与mutex 一起使用,该布尔表达式的读写需受此mutex 保护

    2. mutex 已上锁的时候才能调用wait()

    3. 把判断布尔条件和wait() 放到while 循环中

    示例:

    MutexLock mutex;
    Condition cond(mutex);
    std::deque<int> queue;
    
    int dequeue()
    {
      MutexLockGuard lock(mutex);
      while (queue.empty()) {  // 必须用循环;必须在判断之后再 wait()
        cond.wait(); // 这一步会原子地 unlock mutex 并进入 blocking,不会与 enqueue 死锁
      }
      assert(!queue.empty());
      int top = queue.front();
      queue.pop_front();
      return top;
    }

    对于 signal/broadcast 端:

    1. 不一定要在mutex 已上锁的情况下调用signal 

    2. signal 之前一般要修改布尔表达式

    3. 修改布尔表达式通常要用mutex保护

    void enqueue(int x)
    {
      MutexLockGuard lock(mutex);
      queue.push_back(x);
      cond.notify();
    }

    实现了一个简单的unbounded BlockingQueue

    条件变量是较底层的同步原语,很少直接使用,一般都是用它来实现高层的同步措施,如 BlockingQueue CountDownLatch


    临界区

    临界区是值一个访问共享资源的代码段。当有一个线程访问了临界区之后,其他线程想要访问临界区时会被挂起,直到进入临界区的线程离开。windows API提供了临界区对象结构体CRITICAL_SECTION,常用API有:

    1. 申请一个临界区变量  CRITICAL_SECTION gSection;

    2.InitializeCriticalSection(&gSection),初始化临界区,唯一的参数是指向结构体CRITICAL_SECTION的指针变量(LPCRITICAL_SECTION lpCriticalSection)。

    3.EnterCriticalSection(&gSection),线程进入已经初始化的临界区,并拥有该临界区的所有权。这是一个阻塞函数,如果线程获得临界区的所有权成功,则该函数将返回,调用线程继续执行,否则该函数将一直等待,这样会造成该函数的调用线程也一直等待。如果不想让调用线程等待(非阻塞),则应该使用TryEnterCriticalSection(&gSection)。

    4.LeaveCriticalSection(&gSection),线程离开临界区并释放对该临界区的所有权,以便让其他线程也获得访问该共享资源的机会。一定要在程序不适用临界区时调用该函数释放临界区所有权,否则程序将一直等待造成程序假死。

    5.DeleteCriticalSection(&gSection),该函数的作用是删除程序中已经被初始化的临界区。如果函数调用成功,则程序会将内存中的临界区删除,防止出现内存错误。


    未完待续。。。

    展开全文
  • C++线程同步的几种方式

    千次阅读 2018-05-28 16:32:00
    1.临界区,通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。确保在某个时刻只有一个线程能访问数据。此时其他线程如想访问数据则会被挂起,直到当前线程离开临界区。临界区被释放后,其他...

    1.临界区,通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。确保在某个时刻只有一个线程能访问数据。此时其他线程如想访问数据则会被挂起,直到当前线程离开临界区。临界区被释放后,其他线程继续抢占。

    2.互斥量,和临界区类似,可以保证同一时刻只有一个线程访问数据。类似java中的对象锁。成功获取互斥量的线程可以访问数据,其他线程将被挂起,直到当前线程释放互斥量。互斥量比临界区复杂。因为使用互斥不但仅能够在同一应用程式不同线程中实现资源的安全共享,而且能够在不同应用程式的线程之间实现对资源的安全共享。

    3.信号量,信号量对象对线程的同步方式和前面几种方法不同,信号允许多个线程同时使用共享资源,这和操作系统中的PV操作相同。他指出了同时访问共享资源的线程最大数目。他允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。

    4.事件,事件对象也能够通过通知操作的方式来保持线程的同步。并且能够实现不同进程中的线程同步操作。

    总结:

      1. 互斥量和临界区的作用很相似,但互斥量是能够命名的,也就是说他能够跨越进程使用。所以创建互斥量需要的资源更多,所以假如只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就能够通过名字打开他。

      2. 互斥量(Mutex),信号灯(Semaphore),事件(Event)都能够被跨越进程使用来进行同步数据操作,而其他的对象和数据同步操作无关,但对于进程和线程来讲,假如进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以能够使用WaitForSingleObject来等待进程和线程退出。

      3. 通过互斥量能够指定资源被独占的方式使用,但假如有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,能够根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候假如利用互斥量就没有办法完成这个需要,信号灯对象能够说是一种资源计数器。

    参考链接: C++中四种线程同步的方法

    展开全文
  • sem_wait() 会阻塞当前线程 sem_trywait() 返回错误而不是阻塞调用 sem_timedwait() sem_timedwait的abs_timeout参数指定了调用应该阻塞的时间限制 信号量 信号量 (semaphore) 是一种轻量的同步原件,用于制约对...

    一般,使线程阻塞我们可以使用 while(condition); for(;condition;); 等循环条件使之线程内语句执行在循环处无法向下继续执行,但这样并不是真正意义上的线程阻塞,当前线程仍然在执行,只是在循环语句处不断空耗CPU

    在C中有信号量、互斥量、条件变量、读写锁等可用于线程同步,他们都有对应的可以使之线程阻塞的方法。

    例如C的信号量。C头文件 <semaphore.h>中

    • sem_wait() 会阻塞当前线程
    • sem_trywait() 返回错误而不是阻塞调用
    • sem_timedwait() sem_timedwait的abs_timeout参数指定了调用应该阻塞的时间限制

    在C++中主要有以下方法:
    信号量
    信号量 (semaphore) 是一种轻量的同步原件,用于制约对共享资源的并发访问。在可以使用两者时,信号量能比条件变量更有效率。

    定义于头文件 <semaphore>
    counting_semaphore 实现非负资源计数的信号量
    binary_semaphore 仅拥有二个状态的信号量(typedef)

    其中

    • acquire 减少内部计数器或阻塞到直至能如此
    • try_acquire 尝试减少内部计数器而不阻塞
    • try_acquire_for 尝试减少内部计数器,至多阻塞一段时长
    • try_acquire_until 尝试减少内部计数器,阻塞直至一个时间点

    互斥
    互斥算法避免多个线程同时访问共享资源。这会避免数据竞争,并提供线程间的同步支持。

    定义于头文件 <mutex>

    • lock 锁定互斥,若互斥不可用则阻塞 ,其中lock可锁定多个mutex对象,并内置免死锁算法避免死锁。
    • try_lock 尝试锁定互斥,若互斥不可用则返回 (不阻塞)
    • unlock 解锁互斥

    通常不直接使用 std::mutex ,一般使用 std::unique_lock 、 std::lock_guard 或 std::scoped_lock 互斥器管理器使用。

    • lock_guard 实现严格基于作用域的互斥体所有权包装器
    • scoped_lock 用于多个互斥体的免死锁 RAII 封装器
    • unique_lock 实现可移动的互斥体所有权包装器

    条件变量
    条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续。条件变量始终关联到一个互斥。

    定义于头文件 <condition_variable>

    condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。

    有意修改变量的线程必须

    1. 获得 std::mutex (常通过 std::lock_guard )
    2. 在保有锁时进行修改
    3. 在 std::condition_variable 上执行 notify_one 或 notify_all (不需要为通知保有锁)
      即使共享变量是原子的,也必须在互斥下修改它,以正确地发布修改到等待的线程。

    由上可得,条件变量在线程同步时,需要获得互斥量才能进行。而 unique_lock 这个互斥器管理器允许自由的unlock,所以一般条件变量与unique_lock一起使用。

    • wait 、 wait_for 或 wait_until ,等待操作自动释放互斥,并悬挂线程的执行(阻塞)。
      在这里插入图片描述

    Future
    标准库提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常。这些值在共享状态中传递,其中异步任务可以写入其返回值或存储异常,而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。

    • get 返回结果 ,get 方法等待直至 future 拥有合法结果并(依赖于使用哪个模板)获取它。它等效地调用 wait() 等待结果。(阻塞
    • wait 等待结果变得可用 。阻塞直至结果变得可用。调用后 valid() == true 。
    • wait_for 等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。 阻塞直至经过指定的 timeout_duration,或结果变为可用
    • wait_until 等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。阻塞直至抵达指定的 timeout_time ,或结果变为可用

    this_thread
    在this_thread命名空间下,有this_thread::sleep_for、this_thread::sleep_until、this_thread::yield 三个方法。

    其中前两个可以通过让线程睡眠一段时间而达到阻塞线程的目的。

    后者,可以通过一定的条件使得当前线程让度给其他线程达到阻塞的目的。while (condition) this_thread::yield();

    原子操作(CAS)

    此外,使用原子量实现自旋锁,也可以在一定时间内阻塞线程。

    class CAS	// 自旋锁
    {
    private:
    	std::atomic<bool> flag;	// true 加锁、false 无锁
    public:
    	CAS() :flag(true) {}   // 注意这里初始化为 true,因此,第一次调用 lock()就会阻塞
    	~CAS() {}
    	CAS(const CAS&) = delete;
    	CAS& operator=(const CAS&) = delete;
    
    	void lock()	// 加锁
    	{
    		bool expect = false;
    		while (!flag.compare_exchange_strong(expect, true))
    		{
    			expect = false;
    		}
    	}
    	void unlock()
    	{	
    		flag.store(false);
    	}
    };
    
    展开全文
  • 线程间通信的事件和信号量进行的功能封装,简单易用
  • C++ 线程同步 event事件

    千次阅读 2018-03-22 13:43:26
    一、线程 线程是指进程内的一个执行单元,也是进程内的可调度实体;当进程启动的同时启动了一个线程,叫做主线程或者执行线程;一个进程可以有多个线程,每个线程都共享进程的地址空间,并且共享进程地址空间内的...
  • visual studio C++线程同步
  • C++线程同步的四种方式

    万次阅读 2013-08-06 10:46:28
     (1)线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。  (2)线程互斥是指对于共享的操作系统资源(指的是广义的...
  • 一文搞定c++线程同步机制

    千次阅读 2020-09-08 21:02:05
    c++线程同步机制 同步与互斥 现代操作系统都是多任务操作系统,通常同一时刻有大量可执行实体,则运行着的大量任务可能需要访问或使用同一资源,或者说这些任务之间具有依赖性。 线程同步线程同步是指线程之间...
  • 线程同步的五种方法

    2014-04-01 22:50:54
    本工程中包含了线程同步的五种方法,现在拿出来和大家一起分享,VC6.0编译测试通过,工程中包含了5个小工程,具体讲述每种线程同步方法的具体使用列子,而且有详细的注释。
  • 背景问题:在特定的应用场景下,多线程不进行同步会造成什么问题?通过多线程模拟多窗口售票为例:#include <iostream> #include<pthread.h> #include<stdio.h> #include<stdlib.h> #...
  • C++线程同步的几种方式

    千次阅读 2019-12-26 20:25:35
    文章目录Overviewmutexlock_guardunique_lockcondition_variablefuturepromisepackaged_...C++的多线程同步方式有这么几种: mutex lock_guard unique_lock condition_variable future promise packaged...
  • 使线程同步  在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在...
  • C++11线程同步方式

    千次阅读 2020-02-11 17:57:36
    线程间为什么需要同步?直接来看一个例子: int a = 0; void foo() { for (int i = 0; i < 10000000; ++i) { a += 1; } } int main() { clock_t start, end; start = clock(); thread t1(foo); thread ...
  • C++多线程并发(三)---线程同步之条件变量

    千次阅读 多人点赞 2019-05-03 12:43:12
    在前一篇文章《C++多线程并发编程(二)—线程同步之互斥锁》中解释了线程同步的原理和实现,使用互斥锁解决数据竞争访问问题,算是线程同步的加锁原语,用于排他性的访问共享数据。我们在使用mutex时,一般都会期望...
  • C++11线程同步

    千次阅读 2019-06-02 21:46:29
    线程同步:临界区、互斥量、事件、信号量 2。线程等待:事件、条件变量、while/sleep()、join 条件变量等待线程与通知线程使用不同类型锁:https://blog.csdn.net/lijinqi1987/article/details/78425781 3。...
  • c++线程同步——信号量。非常简单的MFC工程。
  • C++多线程并发(二)---线程同步之互斥锁

    万次阅读 多人点赞 2019-03-20 00:08:29
    一、何为线程同步 在前一篇文章《C++多线程并发编程(一)—线程管理》中解释多线程并发时说到两个比较重要的概念: 多线程并发:在同一时间段内交替处理多个操作,线程切换时间片是很短的(一般为毫秒级),一个...
  • 线程调用类对象 在前面的示例中,我们为线程任务使用了通常的函数。实际上,我们可以使用任何可调用对象或者lambda函数,如下调用类对象的例子: #include #include class MyFunctor { public: void operator()...
  • 讲述了c++开发中多线程的开发技巧。里面有代码实例
  • C++实现线程同步的几种方式

    千次阅读 2018-04-22 14:50:44
    线程同步是指同一进程中的多个线程互相协调工作从而达到一致性。之所以需要线程同步,是因为多个线程同时对一个数据对象进行修改操作时,可能会对数据造成破坏,下面是多个线程同时修改同一数据造成破坏的例子: 1 #...
  • C++中四种线程同步的方法

    千次阅读 2017-11-21 15:16:22
    现在流行的进程线程同步互斥的控制机制,其实是由最原始最基本的4种方法实现的。由这4种方法组合优化就有了.Net和Java下灵活多变的,编程简便的线程进程控制手段。   这4种方法具体定义如下 在《操作系统教程》...
  • 很不错的源码,3种多线程实现同步方法
  • 10分钟,带你掌握C++线程同步

    千次阅读 2018-08-10 11:29:22
    摘要:本文介绍了C++11中如何开启新线程,并详细讲解了线程的基础同步原语:mutex, lock_guard, unique_lock, condition variable和semaphore等。...本文以质数判定服务为例为大家分享C++线程同步措施!   数十...
  • 本程序在多线程中使用事件实现资源访问同步,依次访问操作threadRun02中变量i的值和threadRun01中变量i的值。实现了通过通知操作的方式来保持线程访问资源顺序。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 116,404
精华内容 46,561
关键字:

c++线程同步

c++ 订阅