网络编程---为何条件变量要和互斥量联合使用

为何条件变量要和互斥量联合使用:
条件变量起到了阻塞和唤醒线程的作用,所以通常互斥锁要和条件变量配合。

互斥锁一个明显的缺点是他只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,他常和互斥锁一起使用。
使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。用pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex)

一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。pthread_cond_signal(&m_pthreadCond);

这些线程将重新锁定互斥锁并重新测试条件是否满足(pthread_cond_wait返回)。一般说来,条件变量被用来进行线承间的同步。

可以总结为:两个线程操作同一临界区时,通过互斥锁保护,若A线程已经加锁,B线程再加锁时候会被阻塞,直到A释放锁,B再获得锁运行,进程B必须不停的主动获得锁、检查条件、释放锁、再获得锁、再检查、再释放,一直到满足运行的条件的时候才可以(而此过程中其他线程一直在等待该线程的结束),这种方式是比较消耗系统的资源的。而条件变量同样是阻塞,还需要通知才能唤醒,线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,该线程就休眠了,应该仍阻塞在这里,等待条件满足后被唤醒,节省了线程不断运行浪费的资源。这个过程一般用while语句实现。当线程B发现被锁定的变量不满足条件时会自动的释放锁并把自身置于等待状态,让出CPU的控制权给其它线程。其它线程 此时就有机会去进行操作,当修改完成后再通知那些由于条件不满足而陷入等待状态的线程。这是一种通知模型的同步方式,大大的节省了CPU的计算资源,减少了线程之间的竞争,而且提高了线程之间的系统工作的效率。这种同步方式就是条件变量。

while ( (pThreadPoolObj->m_MsgRecvQueue.size() == 0) && m_shutdown == false)
    {               
        //如果这个pthread_cond_wait被唤醒【被唤醒后程序执行流程往下走的前提是拿到了锁--官方:pthread_cond_wait()返回时,互斥量再次被锁住】,
          //那么会立即再次执行g_socket.outMsgRecvQueue(),如果拿到了一个NULL,则继续在这里wait着();
        if(pThread->ifrunning == false)            
            pThread->ifrunning = true; //标记为true了才允许调用StopAll():测试中发现如果Create()和StopAll()紧挨着调用,就会导致线程混乱,所以每个线程必须执行到这里,才认为是启动成功了;
                            //线程启动起来
        //ngx_log_stderr(0,"执行了pthread_cond_wait-------------begin");
        //所有线程都会卡这里,都会把互斥量释放
        //刚开始执行pthread_cond_wait()的时候,会卡在这里,而且互斥量m_pthreadMutex会被释放掉;这个函数执行通过后又自动获得锁
        pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex); //整个服务器程序刚初始化的时候,所有线程必然是卡在这里等待的;
        //ngx_log_stderr(0,"执行了pthread_cond_wait-------------end");
    }

In Thread1:

pthread_mutex_lock(&m_mutex);
pthread_cond_wait(&m_cond,&m_mutex);
pthread_mutex_unlock(&m_mutex);

In Thread2:

pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);

为什么要与pthread_mutex 一起使用呢?
由于pthread_cond_wait()不是原子操作,这是为了应对 线程1在调用pthread_cond_wait()但线程1还没有进入wait cond的状态的时候,此时线程2调用了 cond_singal 的情况。 如果不用mutex锁的话,这个cond_singal就丢失了。加了锁的情况是,线程2必须等到 mutex 被释放(也就是 pthread_cod_wait() 释放锁并进入wait_cond状态 ,此时线程2上锁) 的时候才能调用cond_singal.

为什么会出现虚假唤醒,为什么要用while来避免虚假唤醒?

虚假唤醒的出现在于生产者的notify并不在临界区内,也就是说,生产者使用临界区保护了修改流水线的这个操作,然后解锁,解锁完毕后才notify。而在这之间是非原子的。

在以下情况:

1).生产者对临界区加锁

2).修改流水线状态

3).生产者解锁

4).notify通知生产者线程

在3)与4)间是有空隙的,如果在3)进行后突然此刻加入了一个新的生产者,这个生产者察觉到流水线的变化,对他进行了消费,然后消费者才notify,notify唤醒了原有的消费者, 但流水线已经为空了,实际上这就是一个虚假唤醒,唤醒后并无工作可做。

因此不能用if来进行条件判断,加入while就可以避免虚假唤醒,在每次唤醒后先判断流水线条件,这样避免了虚假唤醒的情况。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值