C++进阶—>线程同步随笔

       线程同步主要有五种方法:原子访问,临界区,信号量,事件和互斥量;其中原子访问和临界区属于用户模式的同步;信号量,事件和互斥量属于内核模式的同步。

       原子访问是通过将共享资源设置为原子变量,当一个线程访问的时候,其余的线程不得访问。C++使用临界区,信号量,事件和互斥量实现线程同步的时候,即定义相应的同步控制对象句柄,通过获取控制对象是否空闲来决定是否执行线程,若控制对象空闲则获取该对象执行线程,执行完毕后释放该控制对象,若控制对象不空闲,则等待,直到控制对象空闲并获取到控制对象后才执行线程。

       下面简单谈一谈临界区,信号量,事件和互斥量四种方法实现多线程同步或顺序执行的大体思路(理解未必深而透彻,初步理解有待提高仅作为参考)

       对于使用Windows API实现线程同步来说,只是创建了临界区或信号量或事件或互斥量控制对象,使用WaitForSingleObject函数来等待控制对象是否空闲,若空闲则获取其控制对象执行自己的线程函数,若不空闲则持续等待或等待固定时间,由于多线程是通过时间片轮转机制实现的,通过一个控制对象仅仅实现了多线程的同步(不同时访问某个资源或重复执行某条语句),但并没有实现多线程的顺序执行(即线程1、线程2、线程3....等按照顺序执行),对于多线程的顺序执行仅仅创建一个控制对象是不足以满足顺序执行,下面以事件实现三个线程顺序执行阐述:

       创建三个事件控制对象,CreatEvent event1,event2,event3;

线程1监听event1,执行完后释放event1,设置event2为有信号状态;

线程2监听event2,执行完后释放event2,设置event3为有信号状态;

线程3监听event3,执行完后释放event3,设置event1为有信号状态;

依次执行即可实现多线程的顺序执行。

/************使用临界区对象实现多线程同步***************
临界区被初始化后,当程序进入临界区后便拥有临界区的所有权,其余线程无权进入只能等对方释放临界区之后,方可进入临界区拥有其所有权再对临界区进行操作
InitializeCriticalSection()初始化临界区;
EnterCriticalSection()进入临界区;
LeaveCriticalSection()释放临界区所有权并离开临界区;
注意:上述是windows API中相关函数,CCriticalSection类是MFC中定义的临界区类,需要在MFC程序中使用(此程序为控制台程序无法使用MFC类),可以操作临界区,lock锁定临界区、unlock释放临界区
	  临界区为依次访问,不能实现其中一个线程一释放临界区就会被另一个线程访问临界区!不能实现实时监听
********************************************************/

/************使用事件对象实现多线程同步***************
事件对象是指用户在程序中使用内核对象的有无信号状态实现线程的同步临界区被初始化后,当程序进入临界区后便拥有临界区的所有权,其余线程无权进入只能等对方释放临界区之后,方可进入临界区拥有其所有权再对临界区进行操作
CreatEvent()创建并返回事件对象;
SetEvent()将指定的事件设置为有信号状态(有信号状态下其余线程可以访问);
ResetEvent()将指定的事件设置为无信号状态;
除SetEvent函数外,WaitForSingleObject函数等待指定事件。
注意:上述是Windows API函数,CEvent类是MFC实现事件对象的类
	  事件对象为立即访问,一旦事件对象被设置为有信号 立刻会被其余线程访问!能实现实时监听
********************************************************/

/************使用互斥对象实现多线程同步***************
互斥对象还可以在进程间使用,在实现线程同步时包含一个线程ID和一个计数器,线程ID表示拥有互斥对象的线程,计数器表示该互斥对象被同一线程所使用次数
CreatMutex()创建并返回互斥对象;
ReleaseMutex()释放互斥对象句柄;
WaitForSingleObject()对该对象进行请求。
注意:上述是Windows API函数,CMutex类是MFC中的互斥对象类
	  互斥对象为立即访问,一旦互斥对象被释放 立刻会被其它正在等待的线程访问!能实现实时监听
********************************************************/

/************使用信号量实现多线程同步***************
信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。
它指出了同时访问共享资源的线程 最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
在用CreateSemaphore()创建信号量 时即要同时指出允许的最大资源计数和当前可用资源计数。
一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数 就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。
但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目, 不能在允许其他线程的进入,此时的信号量信号将无法发出。
线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可 用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。

CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName) 创建一个信号量  
第一个参数表示安全控制,一般直接传入NULL;
第二个参数表示初始化可用资源数量;
第三个参数表示最大并发数量;
第四个参数表示信号量的名称,传入NULL表示匿名信号量。

OpenSemaphore(DWORD dwDesiredAccess,BOOL bInheritHandle,LPCTSTR lpName) 打开一个信号量  
第一个参数表示访问权限,SEMAPHORE_ALL_ACCESS要求对事件对象的完全访问;SEMAPHORE_MODIFY_STATE 允许使用ReleaseSemaphore函数;SYNCHRONIZE允许同步使用信号机对象。
第二个参数表示信号量句柄继承性,一般传入TRUE即可。
第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。

ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount, LPLONG lpPreviousCount) 释放信号量 
第一个参数是信号量的句柄。
第二个参数表示增加个数,必须大于0且不超过最大资源数量。
第三个参数可以用来传出先前的资源计数,设为NULL表示不需要传出

注意:在CreateSemaphore创建信号量的时候如果第二个参数设置为0则表示可用的信号量资源为0,使用WaitForSingleObject函数无法获取到信号量(因为无可用的资源),此时需要调用OpenSemaphore函数打开信号量,使其可用资源为最大;
	  若不想使用OpenSemaphore函数 则在创建信号量的时候不要将初始化可用资源设置为0即可。
	  信号量机制:在信号量未达到最大并发数的时候,各线程可以同时获取信号量,直到达到了最大并发数后续线程不可再获取信号量,需要使用ReleaseSemaphore函数将当前线程的信号量释放并将信号量可用资源数+1,后续线程可获取信号量执行。
********************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,可以使用互斥量(mutex)来实现全局变量的线程同步。互斥量是一种同步原语,用于保护共享资源不被多个线程同时访问。当一个线程获得了互斥量的锁时,其他线程需要等待该线程释放锁才能继续执行。这样可以确保同一时刻只有一个线程可以访问共享资源。 在引用的代码示例中,可以看到使用了互斥量来保护全局变量tickets的访问。通过在fun1Proc和fun2Proc函数中使用std::mutex类创建互斥量对象,并使用lock()和unlock()函数来锁定和释放互斥量的锁。这样可以确保在每次访问tickets时只有一个线程可以执行,从而避免了数据竞争和不确定的结果。 此外,可以使用条件变量(condition variable)来实现线程之间的通信和同步。条件变量是一种同步原语,用于在多个线程之间进行等待和唤醒操作。当一个线程需要等待某个条件满足时,可以调用wait()函数将自己阻塞,直到其他线程通过notify_one()或notify_all()函数唤醒它。这样可以有效地控制线程的执行顺序和同步。 在引用的代码示例中,没有使用条件变量,而是通过循环判断tickets的值来判断是否继续执行。这种方式并不是最优雅和高效的线程同步方法,因为它会造成不必要的CPU资源浪费。使用条件变量可以更好地实现线程之间的同步和通信,提高程序的性能和可维护性。 总结起来,C++中可以使用互斥量和条件变量来实现全局变量的线程同步。互斥量用于保护共享资源的访问,条件变量用于线程之间的等待和唤醒操作。通过合理地运用这些同步原语,可以确保多线程程序的正确性和可靠性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++多线程线程同步问题](https://blog.csdn.net/sinat_41928334/article/details/107880741)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值