现在的位置: 首页 > 综合 > 正文

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

2013年09月13日 ⁄ 综合 ⁄ 共 2928字 ⁄ 字号 评论关闭

1. 何时Sem不够,还需要使用Mutex?

        假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样:

        如果操作比较复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零. 这种情况下,如果只用mutex, 则t3需要一个循环,每个循环里先取得lock_s,然后检查sum的状态,如果sum>=100,则打印并清零,然后unlock.如果sum& lt;100,则unlock,并sleep()本线程合适的一段时间.这个时候,t0,t1,t2的代码不变,t3的代码如下:

 这种办法有两个问题
1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,只是lock和unlock,然后sleep().这浪费了CPU处理时间.
2) 为了节省CPU处理时间,t3会在探测到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t4才会醒过来.
3) 这样,程序员在设置sleep()时间的时候陷入两难境地,设置得太短了节省不了资源,太长了又降低响应速度.真是难办啊!

这个时候,condition variable内裤外穿,从天而降,拯救了焦头烂额的你!

你首先定义一个condition variable,

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

t0,t1,t2的代码只要后面加两行,像这样:

而t3的代码变成了:

 

注意两点:
1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回.
2) 为什么是while(sum<100),而不是if(sum<100) ?这是因为在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,假设在这个时间差内,还有另外一 个线程t4又把sum减少到100以下了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用 while的作用.

 

其它:

x86原子操作指令的说明

        cmpxchg 比较交换指令,其语义为:

 Inter白皮书上面的说明:

 使用此原子操作可以实现自旋锁,之前有一篇文章中描述了实现:

 

关于smp下的原子操作的一些说明:
      原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断。在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。在对称多处理器(Symmetric Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。
      在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。
      当然,并不是所有的指令前面都可以加lock前缀的,只有ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, 和 XCHG指令前面可以加lock指令,实现原子操作。

 

再其它:

        自旋锁:一直去请求资源,在此过程中cpu不能去调度别的任务去处理,因此是损耗cpu的.

        互斥锁:先去请求资源,如果失败了,立刻进行上下文切换,此时CPU可以有时间去调度别的任务进行处理.

 

 

 

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

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

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

抱歉!评论已关闭.