C++ 线程与pthread条件变量同步

C++ 线程与pthread条件变量同步,c++,c,multithreading,C++,C,Multithreading,我在使用pthread条件变量进行线程同步时遇到一些问题。我有一个线程解析提取一些值的消息,另一个线程使用提取的值增加一些变量。 我使用pthread条件变量来同步这两个线程。 第一个线程看起来像下面的代码段: if(parse_ok){ pthread_mutex_lock(&q_mutex); q = extract_value(); q_changed = true; printf("...awake\n"); pthread_cond_signal(&

我在使用pthread条件变量进行线程同步时遇到一些问题。我有一个线程解析提取一些值的消息,另一个线程使用提取的值增加一些变量。 我使用pthread条件变量来同步这两个线程。 第一个线程看起来像下面的代码段:

if(parse_ok){
  pthread_mutex_lock(&q_mutex);
  q = extract_value();
  q_changed = true;
  printf("...awake\n");
  pthread_cond_signal(&q_cond_var);
  pthread_mutex_unlock(&q_mutex);
 }
while(true){
  pthread_mutex_lock(&q_mutex);                              
  if( !q_changed ){
    std::cout<<"waiting..!"<<std::endl;
    pthread_cond_wait(&q_cond_var, &q_mutex);
  }                                                      
  if(q_changed){
     q_changed = false;
    _actual_q += q;
    _total_q += q;
    _quant_q += q/_fixed_quantity;
  }
  pthread_mutex_unlock(&q_mutex);
}//END of while TRUE                                     
工作线程看起来像下面的代码段:

if(parse_ok){
  pthread_mutex_lock(&q_mutex);
  q = extract_value();
  q_changed = true;
  printf("...awake\n");
  pthread_cond_signal(&q_cond_var);
  pthread_mutex_unlock(&q_mutex);
 }
while(true){
  pthread_mutex_lock(&q_mutex);                              
  if( !q_changed ){
    std::cout<<"waiting..!"<<std::endl;
    pthread_cond_wait(&q_cond_var, &q_mutex);
  }                                                      
  if(q_changed){
     q_changed = false;
    _actual_q += q;
    _total_q += q;
    _quant_q += q/_fixed_quantity;
  }
  pthread_mutex_unlock(&q_mutex);
}//END of while TRUE                                     
while(true){
pthread_mutex_lock(&q_mutex);
如果(!q_已更改){

std::cout这里有几件事可能会让你心烦意乱:

a) printf和cout不是线程安全的,所以它们的输出可能不会反映代码中等待和唤醒的实际顺序

b) 您的代码中没有有效地处理虚假唤醒。我会将
if(!q_changed)
条件更改为
,而(!q_changed)
可以最大限度地减少在虚假唤醒时重新等待条件变量所需的时间(这也将允许您删除最后一个
if(q_changed)
条件块)


编辑(基于@EOF等人的评论):如果使用现代C++/C实现(我假设您没有,因为您使用的是pthreads),那么b)很可能是你的问题。这种情况下的竞争是等待线程可以唤醒然后解锁互斥锁。同时,信号线程获取锁和信号。因为你没有等待条件,所以你没有得到信号。但是请注意,这不是问题-你仍然在处理数据-这只是在本例中,您当时没有向cout输出“waiting”消息。

按照您编写代码的方式,无法保证第二个工作线程在第一个线程发出信号时会处理新的输入。但是,您可以扩展使用
q\u changed
变量来确保发生这种情况

将第一个线程更改为:

if(parse_ok){
    pthread_mutex_lock(&q_mutex);
    while (q_changed) // Always wait in in loop
        pthread_cond_wait(&q_cond_var, &q_mutex);
    q = extract_value();
    q_changed = true;
    pthread_cond_signal(&q_cond_var);
    pthread_mutex_unlock(&q_mutex);
}
while(true){
    pthread_mutex_lock(&q_mutex);
    while( !q_changed ) // Always wait in a loop
        pthread_cond_wait(&q_cond_var, &q_mutex);
    q_changed = false;
    _actual_q += q;
    _total_q += q;
    _quant_q += q/_fixed_quantity;
    pthread_cond_signal(&q_cond_var);     
    pthread_mutex_unlock(&q_mutex);
}
并将第二个工作线程更改为:

if(parse_ok){
    pthread_mutex_lock(&q_mutex);
    while (q_changed) // Always wait in in loop
        pthread_cond_wait(&q_cond_var, &q_mutex);
    q = extract_value();
    q_changed = true;
    pthread_cond_signal(&q_cond_var);
    pthread_mutex_unlock(&q_mutex);
}
while(true){
    pthread_mutex_lock(&q_mutex);
    while( !q_changed ) // Always wait in a loop
        pthread_cond_wait(&q_cond_var, &q_mutex);
    q_changed = false;
    _actual_q += q;
    _total_q += q;
    _quant_q += q/_fixed_quantity;
    pthread_cond_signal(&q_cond_var);     
    pthread_mutex_unlock(&q_mutex);
}

可能希望使q_更改为volatile。C11标准草案n1570:7.21.2 Streams 7每个流都有一个关联的锁,用于在多个执行线程访问流时防止数据争用,并限制由多个线程执行的流操作的交错。一次只能有一个线程持有此锁。该锁重新进入rant:一个线程在给定的时间内可能多次持有锁。
printf()
是线程安全的。@如果您忘记了C++11和C++14合并了C99,只有C++17才是合并的C版本。因此基于C11的规则是不相关的。(为了完整性,C++98/03合并了C89)“JePujull 1”问题是标记C和C++ 2。在这种情况下,C函数没有任何C++中的线程安全,因为在C11之前没有C中的线程。@ EOF 1)我忽略了。2)。