4

我最近一直在使用 pthreads,但有一点我还不太明白。我知道条件变量旨在等待特定条件实现(或“发出信号”)。我的问题是,这与普通互斥锁有什么不同?

据我了解,当条件变为真时,条件变量不只是一个具有额外逻辑的互斥锁来解锁另一个互斥锁(并再次锁定它)吗?

伪代码示例:

mutex mymutex;
condvar mycond;
int somevalue = 0;

onethread()
{
    lock(mymutex);

    while(somevalue == 0)
        cond_wait(mycond, mymutex);

    if(somevalue == 0xdeadbeef)
        some_func()

    unlock(mymutex);
}

otherthread()
{
    lock(mymutex);

    somevalue = 0xdeadbeef;

    cond_signal(mycond);

    unlock(mymutex);
}

所以这个例子中的 cond_wait 解锁mymutex,然后等待mycond被发送信号。

如果是这样,条件变量不只是具有额外魔力的互斥锁吗?还是我对互斥锁和条件变量的基本原理有误解?

4

3 回答 3

14

两种结构完全不同。互斥体旨在提供对某种资源的序列化访问。条件变量旨在允许一个线程通知其他线程某些事件已发生。

于 2009-08-31T00:08:56.883 回答
13

它们并不完全是具有额外魔力的互斥锁,尽管在某些抽象(J​​ava 和 C# 中使用的监视器)中,条件变量和互斥锁被组合成一个单元。条件变量的目的是避免总线等待/轮询,并提示运行时应该“下一个”安排哪些线程。考虑如何在没有条件变量的情况下编写此示例。

while(1) {
  lock(mymutex)
  if( somevalue != 0)
     break;
  unlock(mymutex);
}

if( somevalue == 0xdeadbeef )
  myfunc();

您将在这个线程中处于一个紧密的循环中,消耗大量 CPU,并导致大量锁争用。如果锁定/解锁互斥锁足够便宜,您可能会处于其他线程甚至没有机会获得锁的情况(尽管现实世界的互斥锁通常区分拥有线程和拥有锁,以及具有公平概念所以这在现实中不太可能发生)。

你可以通过坚持睡觉来减少忙碌的等待,

while(1) {
  lock(mymutex)
  if( somevalue != 0)
     break;
  unlock(mymutex);
  sleep(1); // let some other thread do work
}

但是睡多久才合适呢?你基本上只是在猜测。运行时间也不能告诉你为什么在睡觉,或者你在等待什么。条件变量让运行时至少在一定程度上了解当前哪些线程对同一事件感兴趣。

于 2009-08-31T00:12:09.810 回答
3

简单的答案是您可能希望从条件变量中唤醒多个线程,但互斥锁只允许一个线程执行受保护的块。

于 2009-08-31T00:27:47.397 回答