windows多线程同步互斥--总结

秒杀多线程面试题系列

参考JustDoIT —— 大部分内容

《Windows核心编程》线程同步对象速查表

对象
何时处于未触发状态何时处于触发状态WaitForSingleObject副作用内核对象
自动重置事件ResetEvent,PulseEvent或者等待成功SetEvent,PulseEvent重置通知
手动重置事件ResetEvent,PulseEventSetEvent,PulseEvent没有
自动重置可等待计时器CancelWaitableTimer或等待成功SetWaitableTimer重置计时器
手动重置可等待计时器CancelWaitableTimerSetWaitableTimer没有
信号量等待成功时计数大于0的时候(ReleaseSemaphore)计数器减1
互斥量等待成功时不为线程占用时(ReleaseMutex)把所有权交给线程
关键段等待成功时((Try)EnterCriticalSection)不为线程占用时(LeaveCriticalSection)把所有权交给线程×
SRWLock等待成功时(AcquireSRWLock(Exclusive))不为线程占用时(ReleaseSRWLock(Exclusive)把所有权交给线程×
条件变量等待成功(SleepConditionVariable*)被唤醒时(Wake(All)ConditionVariable)没有×

一 同步互斥区别

同步与互斥的区别和联系

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

 秒杀多线程第九篇 经典线程同步总结 关键段 事件 互斥量 信号量

当线程并发执行时,由于资源共享和线程协作,使用线程之间会存在以下两种制约关系。

(1).间接相互制约。一个系统中的多个线程必然要共享某种系统资源,如共享CPU,共享I/O设备,所谓间接相互制约即源于这种资源共享,打印机就是最好的例子,线程A在使用打印机时,其它线程都要等待。

(2).直接相互制约。这种制约主要是因为线程之间的合作,如有线程A将计算结果提供给线程B作进一步处理,那么线程B在线程A将数据送达之前都将处于阻塞状态。

间接相互制约可以称为互斥,直接相互制约可以称为同步,对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程操作完毕,这其实就是线程的同步了。因此同步包括互斥,互斥其实是一种特殊的同步。

二 同步互斥的方法

分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。

注:因此,效率上,临界区比互斥量等要高。

用户模式下的方法有:原子操作、临界区、读写锁,条件变量

内核模式下的方法有:互斥量、信号量、事件(手动和自动),可等待计时器(手动和自动)

三 临界区、互斥量、信号量、事件 对比

image

1、关于线程所有权属性:即某个线程获得该同步工具后,在他释放该工具前可以多次进入想访问的资源,一般来说具有所有权属性的工具不用于线程同步,只用于互斥,具体可以参考本文最前面的几篇博客

2、内核模式下的工具可以用于不同进程的线程之间的同步互斥,用户模式则只能用于相同进程的线程之间

3、只有互斥量在线程异常退出时,会释放对该工具的所有权,其他线程可以继续获取。其他的工具在线程异常退出时,其占有的工具不会释放,其他线程需要一直等待

4、事件分为自动和手动,如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。

四、死锁

百度百科

 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

虽然进程在运行过程中,可能发生死锁,但死锁的发生也必须具备一定的条件,死锁的发生必须具备以下四个必要条件。

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

一个典型的例子是:

线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象.

死锁可以用LockCop来检测,其源码地址为https://github.com/lattesir/WindowsViaCPP/tree/master/09-LockCop

注:该工具使用了Windows Vista/ 7提供的WCT API,故需要在Windows Vista/ 7系统运行LockCop检测工具。

windows 多线程编程的几点经验 (防止死锁)

1) 不要在线程函数体内操作MFC控件,不要再线程里面调用UpdateData函数更新用户界面,而应该尽量采用发送消息的方式,在主线程的消息响应函数中操作控件;

注:Winform/WPF中在线程中更新界面会抛出异常,解决办法也是用委托。

2)不建议采用SendMessage往主线程发送消息,因为它是同步的,阻塞的,可以考虑采用PostMessage代替;

3)线程退出时,尽量不要使用TerminateThread函数,而尽可能的让线程自己退出;

注:在线程中有malloc/new等操作,强行终止,1会导致内存泄露,2是因为整个进程在分配和回收内存时,都要用同一把锁,如果TerminateThread之后再new很有可能会死锁。CloseHandle(),TerminateThread(),ExitThread()的区别

4) 当线程退出时,必须先等待工作者线程退出,主线程才退出,但是在主线程里面不要使用WaitForSingleObject或WaitForMultiObjects等待线程结束,因为它可能造成死锁,当主线程使用这两个函数时,主线程就挂起了,尤其在第 (1), (2) 种情况下,工作者线程还在调用主线程里面的资源,这样造成死锁;

5) 为了防止退出死锁的发生,尽量使用MsgWaitForMultipleObjects函数,因为该函数等待时,可以等待线程句柄 有信号,而且还可以等待消息,不会造成死锁;

转载于:https://my.oschina.net/shanlilaideyu/blog/481608

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值