四种多线程同步机制

四种多线程同步机制参考一 1 nbsp 临界区 CriticalSect 因为 CriticalSect 不是内核对象 所以只能用来同一进程内线程间的同步 不能用来多个不同进程间的线程的同步 2 如果在 CriticalSect 中间突然程序 crash 或是 exit 而没有调用 LeaveCritica 则结果是该线程所对应的内核不能被释放 该线程成为死线程 3 要比其他

参考一

1. 临界区CriticalSections

1) 因为Critical Sections不是内核对象,所以只能用来同一进程内线程间的同步,不能用来多个不同进程间的线程的同步。

2) 如果在Critical Sections中间突然程序crash或是exit而没有调用LeaveCriticalSection,则结果是该线程所对应的内核不能被释放,该线程成为死线程。

3) 要比其他的内核对象的速度要快

2. 互斥量Mutex   
1)互斥对象(mutex)内核对象能够确保线程拥有对单个资源的互斥访问权。实际上互斥对象是因此而得名的。互斥对象包含一个使用数量,一个线程ID和一个递归计数器。
 2) 互斥对象的行为特性与关键代码段相同,但是互斥对象属于内核对象,而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。但是这也意味着不同进程中的多个线程能够访问单个互斥对象,并且这意味着线程在等待访问资源时可以设定一个超时值。

 3) ID用于标识系统中的哪个线程当前拥有互斥对象,递归计数器用于指明该线程拥有互斥对象的次数。

 4) 互斥对象有许多用途,属于最常用的内核对象之一。通常来说,它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块,内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权,这样就能够保证数据的完整性。

5)互斥对象的使用规则如下:

• 如果线程ID是0(这是个无效ID),互斥对象不被任何线程所拥有,并且发出该互斥对象的通知信号。

• 如果ID是个非0数字,那么一个线程就拥有互斥对象,并且不发出该互斥对象的通知信号。

1)在所有的内核对象中,事件内核对象是个最基本的对象。它们包含一个使用计数(与所有内核对象一样),一个用于指明该事件是个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。

2)事件能够通知一个操作已经完成。有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。

3)当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。

 4)Microsoft为自动重置的事件定义了应该成功等待的副作用规则,即当线程成功地等待到该对象时,自动重置的事件就会自动重置到未通知状态。这就是自动重置的事件如何获得它们的名字的方法。通常没有必要为自动重置的事件调用ResetEvent函数,因为系统会自动对事件进行重置。但是,Microsoft没有为人工重置的事件定义成功等待的副作用,所以需要调用ResetEvent()。

4. 信号量Semaphore

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

参考二

1、  Event

用事件(Event)来同步线程是最具弹性的了。一个事件有两种状态:激发状态和未激发状态。也称有信号状态和无信号状态。事件又分两种类型:手动重置事件和自动重置事件。手动重置事件被设置为激发状态后,会唤醒所有等待的线程,而且一直保持为激发状态,直到程序重新把它设置为未激发状态。自动重置事件被设置为激发状态后,会唤醒“一个”等待中的线程,然后自动恢复为未激发状态。所以用自动重置事件来同步两个线程比较理想。MFC中对应的类为 CEvent.。CEvent的构造函数默认创建一个自动重置的事件,而且处于未激发状态。共有三个函数来改变事件的状态:SetEvent,ResetEvent和PulseEvent。用事件来同步线程是一种比较理想的做法,但在实际的使用过程中要注意的是,对自动重置事件调用SetEvent和PulseEvent有可能会引起死锁,必须小心。

2、  Critical Section

使用临界区域的第一个忠告就是不要长时间锁住一份资源。这里的长时间是相对的,视不同程序而定。对一些控制软件来说,可能是数毫秒,但是对另外一些程序来说,可以长达数分钟。但进入临界区后必须尽快地离开,释放资源。如果不释放的话,会如何?答案是不会怎样。如果是主线程(GUI线程)要进入一个没有被释放的临界区,呵呵,程序就会挂了!临界区域的一个缺点就是:Critical Section不是一个核心对象,无法获知进入临界区的线程是生是死,如果进入临界区的线程挂了,没有释放临界资源,系统无法获知,而且没有办法释放该临界资源。这个缺点在互斥器(Mutex)中得到了弥补。Critical Section在MFC中的相应实现类是CcriticalSection。CcriticalSection::Lock()进入临界区,CcriticalSection::UnLock()离开临界区。

3、  Mutex

互斥器的功能和临界区域很相似。区别是:Mutex所花费的时间比Critical Section多的多,但是Mutex是核心对象(Event、Semaphore也是),可以跨进程使用,而且等待一个被锁住的Mutex可以设定 TIMEOUT,不会像Critical Section那样无法得知临界区域的情况,而一直死等。MFC中的对应类为CMutex。Win32函数有:创建互斥体CreateMutex() ,打开互斥体OpenMutex(),释放互斥体ReleaseMutex()。Mutex的拥有权并非属于那个产生它的线程,而是最后那个对此 Mutex进行等待操作(WaitForSingleObject等等)并且尚未进行ReleaseMutex()操作的线程。线程拥有Mutex就好像进入Critical Section一样,一次只能有一个线程拥有该Mutex。如果一个拥有Mutex的线程在返回之前没有调用ReleaseMutex(),那么这个 Mutex就被舍弃了,但是当其他线程等待(WaitForSingleObject等)这个Mutex时,仍能返回,并得到一个 WAIT_ABANDONED_0返回值。能够知道一个Mutex被舍弃是Mutex特有的。

4、  Semaphore

信号量是最具历史的同步机制。信号量是解决producer/consumer问题的关键要素。对应的MFC类是Csemaphore。Win32函数 CreateSemaphore()用来产生信号量。ReleaseSemaphore()用来解除锁定。Semaphore的现值代表的意义是目前可用的资源数,如果Semaphore的现值为1,表示还有一个锁定动作可以成功。如果现值为5,就表示还有五个锁定动作可以成功。当调用Wait…等函数要求锁定,如果Semaphore现值不为0,Wait…马上返回,资源数减1。当调用ReleaseSemaphore()资源数加1,当时不会超过初始设定的资源总数。





版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218033.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午8:12
下一篇 2026年3月18日 上午8:12


相关推荐

  • 使用hexo和码云pages搭建个人博客

    使用hexo和码云pages搭建个人博客

    2021年3月12日
    142
  • java运行时异常和非运行时异常区别_常用的运行时异常

    java运行时异常和非运行时异常区别_常用的运行时异常1.Java异常机制Java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。Java中的异常分为两大类:错误Error和异常Exception,Java异常体系结构如下图所示:图片来源:http://blog.csdn.net/wuwenxiang91322/article/details/103463372.Throwab

    2022年9月30日
    4
  • 部分经典vbs代码

    部分经典vbs代码部分经典vbs代码一、上代码:vbs代码,即VBScriptSetWshShell=WScript.CreateObject(“WScript.Shell”)WshShell.AppActivate”@窗口标题”fori=1to50WScript.Sleep200WshShell.SendKeys”^v”WshShell.SendKeysiWshShell.SendKeys”%s”Next二、操作步骤:打开Q_Q聊天窗口,拉出到独立窗口;新建文档,复制代码,根据

    2022年6月10日
    49
  • CentOS6.5下安装tomcat7

    CentOS6.5下安装tomcat7

    2021年6月11日
    80
  • ftp上传下载工具,6款最值得推荐的Windows端ftp上传下载工具

    ftp上传下载工具,6款最值得推荐的Windows端ftp上传下载工具ftp上传下载工具是一种文件传输下载方式,它是TCP/IP协议栈的一部分;其中FTP又由两部分组成,一部分是FTP的服务器,另一部分是FTP的客户端!它能够高效安全地进行文件传输下载操作!可以使用服务器管理工具来作为FTP的客户端,进行FTP的操作,实现FTP的下载安装等!第一款:iis7服务器管理软件iis7远程桌面管理软件,是一款绿色小巧,功能实用的FTP工具软件,其界面简洁,操作方便,它支持FTP批量上传下载,它可以同时连接多台ftp服务器进行文件传输工作,还可以在线解压缩文件,支持文件查找,在线

    2022年5月27日
    43
  • pycharm-professional-2021.12.13激活【2021.10最新】

    (pycharm-professional-2021.12.13激活)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html23EQQJJI0G-eyJsaWN…

    2022年3月30日
    56

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号