C++ 线程与pthread条件变量同步
我在使用pthread条件变量进行线程同步时遇到一些问题。我有一个线程解析提取一些值的消息,另一个线程使用提取的值增加一些变量。 我使用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(&
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)。