互斥是需要保护的条件变量(Mutex are needed to protect the Condi

2019-07-29 10:47发布

正如有人说,互斥是保护条件变量需要。

被声明为这里实际条件变量的引用pthread_cond_t
要么
一个正常的共享变量count ,其值决定的信令,并等待。

Answer 1:

在这里声明为pthread_cond_t的或正常的共享变量计,其值决定信令和等待实际条件变量的引用?

基准是两者。

互斥锁使得它使共享变量( count在你的问题),可以检查,如果该变量的值不符合期望的状态,其内部执行上述等待pthread_cond_wait()将相对于该检查原子发生。

正在解决与互斥的问题是,您有需要是原子的两个独立的操作:

  1. 检查的条件count
  2. 等待insode pthread_cond_wait()如果条件尚未满足。

一个pthread_cond_signal()不“坚持” -如果没有线程等待上pthread_cond_t对象,信号不执行任何操作。 所以,如果没有做以上列举的原子相对于这两个操作一个互斥体彼此你会发现自己在以下情况:

  • 线程A想做一件事,一旦count为非零
  • 当它增加线程B将信号count (将设置count为零以外的东西)

    1. 线程“A”检查count ,并发现它是零
    2. 之前的“A”得到调用pthread_cond_wait() ,线程“B”走来和增量count为1,调用pthread_cond_signal() 这调用实际上什么也不做的后果,因为“A”是不是等待的pthread_cond_t对象呢。
    3. “A”调用pthread_cond_wait() ,但由于条件变量信号不记得,就在这一点上阻止和等待已经来去匆匆的信号。

互斥锁(只要所有线程都遵守规则),使得它使项目#2无法项目1和3之间发生的唯一方法是线程“B”将有机会递增count或者是前一看count或“A”后,已经等待信号。



Answer 2:

条件变量必须始终与互斥相关的,以避免其中线程准备等待条件变量的竞争状态,而另一个线程信号的状态之前的第一个线程上,它实际上等待。

更多信息点击这里

一些示例:

线程1(等待状态)

pthread_mutex_lock(cond_mutex);
while(i<5)
{
 pthread_cond_wait(cond, cond_mutex);
}
pthread_mutex_unlock(cond_mutex);

线程2(信号)的条件

pthread_mutex_lock(cond_mutex);
 i++;
if(i>=5)
{
  pthread_cond_signal(cond);
}
pthread_mutex_unlock(cond_mutex);

正如可以在与上述相同看到,互斥保护变量的“i”是条件的原因。 当我们看到条件不符合,我们进入一个条件等待,它隐释放互斥锁,并从而使线程执行的信令来获得关于“我”的互斥和工作,并避免竞争状态。

现在,按你的问题,如果信号线的信号首先,它应该这样做,否则第一个线程可能只是简单地检查车况,并认为它没有被满足,可能会去的条件等待,并且由于之前获取互斥第二线程已经暗示它,没有人会后有信号,它和第一个线程将继续等待forever.So,在这个意义上,互斥是两个条件:条件变量。



Answer 3:

每个并行线程文档的互斥体不分离的原因是,有通过结合他们显著的性能提升,他们想到的是,因为共同的竞争条件,如果你不使用互斥体,它几乎总是会无论如何都要完成。

https://linux.die.net/man/3/pthread_cond_wait

互斥和条件变量的特性

有人建议互斥量采集和发布,从条件等待脱钩。 这被拒绝,因为它是,事实上,有利于实现实时操作的综合性质。 这些实施方式可以以原子移动条件变量和以这样的方式该互斥是透明的呼叫者之间的高优先级的线程。 这可以防止不必要的上下文切换,当等待线程发出信号提供了一个互斥体的更多确定性的收购。 因此,公平和优先问题,可以直接由调度纪律处理。 此外,在当前的状态等待操作与现存的实践。



Answer 4:

我认为,一个更好的用例可能有助于更好地解释条件变量及其相关互斥。

我使用POSIX条件变量来实现所谓的屏障同步 。 基本上,我用它在一个应用程序,我有15个(数据平面)线程都做同样的事情,我想他们都等到所有数据的飞机已经完成了初始化。 一旦他们都完成了他们的(内部)数据平面初始化,然后就可以开始处理数据。

下面是代码。 请注意,我复制的算法从升压,因为我在这个特殊的应用程序不可能使用的模板:

void LinuxPlatformManager::barrierSync()
{
  // Algorithm taken from boost::barrier

  // In the class constructor, the variables are initialized as follows:
  //   barrierGeneration_ = 0;
  //   barrierCounter_ = numCores_; // numCores_ is 15
  //   barrierThreshold_ = numCores_;


  // Locking the mutex here synchronizes all condVar logic manipulation
  // from this point until the point where either pthread_cond_wait() or 
  // pthread_cond_broadcast() is called below
  pthread_mutex_lock(&barrierMutex_);

  int gen = barrierGeneration_;

  if(--barrierCounter_ == 0)
  {
    // The last thread to call barrierSync() enters here,
    // meaning they have all called barrierSync()
    barrierGeneration_++;
    barrierCounter_ = barrierThreshold_;

    // broadcast is the same as signal, but it signals ALL waiting threads
    pthread_cond_broadcast(&barrierCond_);
  }

  while(gen == barrierGeneration_)
  {
    // All but the last thread to call this method enter here
    // This call is blocking, not on the mutex, but on the condVar
    // this call actually releases the mutex
    pthread_cond_wait(&barrierCond_, &barrierMutex_);
  }

  pthread_mutex_unlock(&barrierMutex_);
}

发现,每一个入射到螺纹barrierSync()方法锁定互斥,这使得互斥锁和呼叫要么之间的一切pthread_cond_wait()pthread_mutex_unlock()原子。 还要注意的是,互斥体被释放/解锁pthread_cond_wait()提到这里 。 在这个环节也提到,如果调用的行为是不确定的 pthread_cond_wait()而不必首先锁定互斥。

如果pthread_cond_wait()没有释放互斥锁,那么所有的线程将阻塞调用pthread_mutex_lock()在开始时barrierSync()方法,并且它不会是能够降低barrierCounter_变量(也操纵相关的增值经销商)原子(也不是线程安全的方式)知道有多少线程都称为barrierSync()

因此,要总结这一切,与条件变量相关的互斥体用于保护条件变量本身,而是它是用来做与条件(相关逻辑barrierCounter_等)原子和线程安全的。 当线程阻塞等待条件要成为真正的,他们实际上是在阻止条件变量,而不是相关的互斥。 并调用pthread_cond_broadcast/signal()将解除对方。

这是与其他资源pthread_cond_broadcast()pthread_cond_signal()额外的参考。



文章来源: Mutex are needed to protect the Condition Variables