线程与pthread条件变量同步

时间:2016-07-21 18:21:36

标签: 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(&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                                     

此代码大部分时间都能正常运行。 有时会发生这种情况,当我收到很多消息时,一个接一个地,睡眠线程会跳过一些觉醒。在工作线程完成工作之前,我是否需要一些信号量来阻止接收线程?怎么样? 提前谢谢。

2 个答案:

答案 0 :(得分:2)

有几件事可能会在这里咬你:

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

b)在您的代码中无法有效处理虚假唤醒。我将if( !q_changed )条件更改为while (!q_changed),以最大限度地缩短您在条件变量上重新等待的时间(如果虚假唤醒)(这也可以让您删除最后一个{{}} if (q_changed) 1}}条件块)。

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

答案 1 :(得分:1)

编写代码的方式,没有保证第二个工作线程每次第一个线程发出信号时都会处理新输入。但是,您可以扩展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);
}

将你的第二个工作线程更改为:

try
{
    string soap = "<BigXmlSOAPHeader></BigXmlSOAPHeader>"
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ws_uri);
    ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) =>
    {
        return true;
    };
    byte[] bytes;
    bytes = System.Text.Encoding.ASCII.GetBytes(soap);
    request.ContentType = "text/xml; encoding='utf-8'";
    request.Timeout = 1000000000;
    request.ContentLength = bytes.Length;
    request.Method = "POST";
    Stream requestStream = request.GetRequestStream(); // it fails here
    requestStream.Write(bytes, 0, bytes.Length);
    requestStream.Close();
    HttpWebResponse response;
    response = (HttpWebResponse)request.GetResponse();
    Stream responseStream = response.GetResponseStream();
    XmlTextReader reader = new XmlTextReader(responseStream);
}
catch (Exception ex)
{
  DoSomethingWithException(ex);
}