互斥锁与信号量的区别
起因是阅读webserver的一个作者的源码时,发现它在线程池中对于任务队列中的添加任务操作是互斥锁与信号量搭配使用的,心里有些疑惑,不知道为什么二者要同时使用,互斥锁可以保证资源的独占式访问,那么有了互斥锁应该就不会出现修改任务队列时,多线程抢占的情况了吧,为什么还要用信号量?
1. 同步和互斥:
- 互斥:互斥锁
多线程执行共享变量的这段代码可能会导致竞争状态,因此我们将此段代码称为临界区(criticalsection),它是执行共享资源的代码片段,一定不能给多线程同时执行。
所以我们希望这段代码是互斥(mutualexclusion)的,也就说执行临界区(criticalsection)代码段的只能有一个线程,其他线程阻塞等待,达到排队效果。
互斥并不只是针对多线程的竞争条件,同时还可用于多进程,避免共享资源混乱。
- 同步:信号量
互斥解决了「多进程/线程」对临界区使用的问题,但是它没有解决「多进程/线程」协同工作的问题
我们都知道在多线程里,每个线程一定是顺序执行的,它们各自独立,以不可预知的速度向前推进,但有时候我们希望多个线程能密切合作,以实现一个共同的任务。
所谓同步,就是「多进程/线程间」在一些关键点上可能需要互相等待与互通消息,这种相互制约的等待与互通信息称为「进程/线程」同步。
举个例,有两个角色分别是研发、质量管控,质量管控测试功能,需要等研「发完成开发」,研发要修bug也要等质量管控「测试完成提交BUG」,正常流程是研发完成开发,通知质量管控进行测试,质量管控测试完成,通知研发人员修复bug。
- 二者区别:
互斥:某一资源同时只允许一个访问者对其进行访问,具有性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:互斥的基础上,通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥。
2. 信号量与互斥锁:
互斥锁(Mutex)保证了使用资源线程的唯一性和排他性,但是无法限制资源释放后其他线程申请的顺序问题,所以是无序的。
而信号量(Semaphore)一般就是互斥的(少许情况读取是可以同时申请的),其保证了线程执行的有序性,可以理解为从一到多的进步,像比较有名的理发厅问题,我们就需要设一个Integer而非Boolean,因为理发厅里面的座椅不可能只有一张。
互斥锁必须由单个线程获取和释放。
信号量是由单个线程释放,另一个线程获取,保证线程同步。
信号量是互斥的进步,Semaphore=1时可以看成互斥锁。
信号量(semaphore[ˈseməfɔ:(r)])用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。而互斥锁(Mutual exclusion,缩写 Mutex)是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。尽管两个概念有点类似,但是他们的侧重点不一样,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
参考:
多线程编程互斥与同步的概念和区别
信号量和互斥锁的区别
信号量(Semaphore)和互斥锁(Mutex)的异同

浙公网安备 33010602011771号