2 互斥锁和条件变量实现线程同步

第二章主要讲的是互斥量和条件变量保证线程同步。
一般,我们把锁创建销毁,加锁解锁用类封装起来。一方面 ,RAII手法保证锁生效期间等于作用域,不会忘记解锁。另一方面,其他的逻辑判断也可以在类中实现。比如加锁后的线程或协程加到睡眠队列中,然后返回主协程;解锁后从队列中弹出,唤醒该协程等。

   pthread_mutex_init(&m_Mutex, NULL);
   pthread_mutex_destroy(&m_Mutex);
   pthread_mutex_lock(&m_Mutex)pthread_mutex_unlock(&m_Mutex)

互斥器一般希望尽快拿到锁访问解锁,而条件变量是为了等待某个条件成立。需要和mutex结合使用,一般用来实现高层的同步措施比如阻塞队列,倒计时。倒计时用在主线程发起多个子线程,子线程完成一定任务,主线程继续执行。
主要函数,wait()等待计数值变为0.
Mutex lock(mutex);
while(count>0)
{
condition.wait();
}

举个例子:
在应用程序中有4个进程thread1,thread2,thread3和thread4,有一个int类型的全局变量iCount。iCount初始化为0,thread1和thread2的功能是对iCount的加1,thread3的功能是对iCount的值减1,而thread4的功能是当iCount的值大于等于100时,打印提示信息并重置iCount=0。
如果没有条件变量,应该是

thread1/2while (1)
       {
             pthread_mutex_lock(&mutex);
             iCount++; 这个变量可以被多个线程看到,所以操作时需要加锁
             pthread_mutex_unlock(&mutex);
       }
thread4:
       while(1)
       {
             pthead_mutex_lock(&mutex);
             if (100 <= iCount)
             {
                   printf("iCount >= 100\r\n"); 通知大家
                   iCount = 0;
                   pthread_mutex_unlock(&mutex);
             }
             else
             {
                   pthread_mutex_unlock(&mutex);
             }
       }

可以看到4线程不停在轮询,每次都要加锁解锁,不仅CPU浪费,而且影响并发性。可以sleep缓解,但是导致可能大于100还没来得及通知。
条件变量使用如下:

thread1/2:
       while(1)
       {
               pthread_mutex_lock(&mutex);
               iCount++;
               pthread_mutex_unlock(&mutex);
               if (iCount >= 100)
               {
                      pthread_cond_signal(&cond);
               }
       }         
thread4:
       while (1)
       {
              pthread_mutex_lock(&mutex);
              while(iCount < 100)
              {
                     pthread_cond_wait(&cond, &mutex);
              }
              printf("iCount >= 100\r\n");
              iCount = 0;
              pthread_mutex_unlock(&mutex);
       }

当iCount < 100时,会调用pthread_cond_wait。而pthread_cond_wait它会释放mutex,然后等待条件变为真返回。当返回时会再次锁住mutex。因为pthread_cond_wait会等待,从而不用一直的轮询,减少CPU的浪费。在thread1和thread2中的函数pthread_cond_signal会唤醒等待cond的线程(即thread4),这样当iCount一到大于等于100就会去唤醒thread4。从而不致出现iCount很大了,thread4才去处理。
为什么是while不是if, while(iCount < 100)
因为可能存在唤醒和返回之间有时间差,这段时间有可能又被3线程减到小于100,所以需要再加锁判断一次。还有一种解释是虚假唤醒,因为还可能被其他信号唤醒。

为什么必须和互斥量一起使用?
因为有可能线程4在进入循环后,但是还没有执行到wait(),这时就已经大于100发信号了,这样就收不到了。所以加锁后,必须等到wait()执行,解锁,然后才能发信号,这样就不会丢失了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值