多线程编程的原则以及Sem信号量和Mutex互斥锁的区别 (一)

本文探讨了多线程编程中使用Mutex和Sem信号量的原则和区别。提出了设计架构时应尽量使用Mutex,避免循环死锁、数据不同步等问题。同时,分析了Mutex和Sem在Linux下通过futex实现的机制,指出Mutex在解锁时更符合futex的初衷,仅在需要时进行系统调用。文章通过示例代码解释了Mutex和Sem在解锁操作上的差异,强调了信号量在特定情况下的系统调用不可避免。
摘要由CSDN通过智能技术生成

1. 尽可能的使用mutex理念去设计架构
2. 容易发生的问题
   A. 循环死锁(互斥锁)
   B. 非递归死锁
   C. 数据不同步
   D. 过于积极的垃圾回收,内存清理
3. 几个原则
   A. 操作尽可能私有化
   B. Public方法是在任何Thread、任何时刻可以调用的
   C. 尽可能的使用mutex方式,而非信号量机制
   D. 必须要对潜在的假设进行判断,是否符合实际条件?
   E. 获得锁之后,尽可能的少操作,以避免在get()内部继续调用资源锁

4.Sem与Mutex处理上有何优劣

   找时间总结了一下,如下表:(难免有不足,还请多多指教!)

            Sem            Mutex
Sem功能强大,定位问题比较困难Mutex功能机制比较稳定,容易定位问题
对资源池的共享进行保护对单一资源进行控制
进程间通信、线程间通信线程间通信
多线程多任务 同步多线程多任务 互斥
可以进行一些计算或者数据处理肯定是锁住某一资源

5.Sem与Mutex的实现机制

        在Linux下,信号量和线程互斥锁的实现都是通过futex系统调用。

        futex(快速用户区互斥的简称)是一个在Linux上实现锁定和构建高级抽象锁如信号量和POSIX互斥的基本工具。它们第一次出现在内核开发的2.5.7版;其语义在2.5.40固定下来,然后在2.6.x系列稳定版内核中出现。

        Futex 是fast userspace mutex的缩写,意思是快速用户空间互斥体。Linux内核把它们作为快速的用户空间的锁和信号量的预制构件提供给开发者。Futex非常基础,借助其自身的优异性能,构建更高级别的锁的抽象,如POSIX互斥体。大多数程序员并不需要直接使用Futex,它一般用来实现像NPTL这样的系统库。

        Futex 由一块能够被多个进程共享的内存空间(一个对齐后的整型变量)组成;这个整型变量的值能够通过汇编语言调用CPU提供的原子操作指令来增加或减少,并且一个进程可以等待直到那个值变成正数。Futex 的操作几乎全部在应用程序空间完成;只有当操作结果不一致从而需要仲裁时,才需要进入操作系统内核空间执行。这种机制允许使用 futex 的锁定原语有非常高的执行效率:由于绝大多数的操作并不需要在多个进程之间进行仲裁,所以绝大多数操作都可以在应用程序空间执行,而不需要使用(相对高代价的)内核系统调用。

        futex保存在用户空间的共享内存中,并且通过原子操作进行操作。在大部分情况下,资源不存在争用的情况下,进程或者线程可以立刻获得资源成功,实际上就没有必要调用系统调用,陷入内核了。实际上,futex的作用就在于减少系统调用的次数,来提高系统的性能。6.Sem与Mutex的实现原理

        线程互斥锁pthread_mutex_t的实现原理:

        信号量sem_t的实现原理:

对比,pthread_mutex_unlock()和sem_post()的实现,我们发现一个不同点,sem_post()无论如何都会调用futex_wake(),进行系统调用。但是pthread_mutex_unlock()却符合futex的初衷,只有在需要仲裁的时候才调用futex_wake()。那么什么是仲裁条件呢?

前面说过信号量和线程互斥锁语义上的区别在于信号量的value>=0,而线程互斥锁的value可以为负数。
        对于lock操作,这两个倒是没有多少差别。信号量只要value>0就可以获得资源,线程互斥锁需要value=1。
       但是对于unlock操作,这两个就有一些差别了。信号量和线程互斥锁,都会增加对应的value。如果加1后,value为1,对于线程互斥锁来讲,实际上表明资源可用,并且之前没有其他的线程在等待这个资源;否则说明还有其他线程在等待这个资源,需要调用futex系统调用唤醒它们。但是对于信号量,由于value必须>=0。那么加1后,即使value为1,也无法判定现在没有其他的进程或线程正在等待资源,所以必须调用futex系统调用。例如:

上面sem的value初始化为1,但是有两个线程争用资源。那么第一个线程获得资源成功,当它unlock的时候,sem的value变为1。但是,这个时候,实际上还有一个线程在等待资源。因此,必须要进行futex_wake()系统调用,唤醒等待资源的线程。

 

本文参考了以下博客的内容,在此表示感谢!

    http://www.eetop.cn/blog/html/04/343504-14125.html

    http://dev.firnow.com/course/6_system/linux/Linuxjs/20090901/173322.html

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值