我在使用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
此代码大部分时间都能正常运行。 有时会发生这种情况,当我收到很多消息时,一个接一个地,睡眠线程会跳过一些觉醒。在工作线程完成工作之前,我是否需要一些信号量来阻止接收线程?怎么样? 提前谢谢。
答案 0 :(得分:2)
有几件事可能会在这里咬你:
a)printf和cout不是线程安全的,因此它们的输出可能无法反映代码中等待和唤醒的实际顺序。
b)在您的代码中无法有效处理虚假唤醒。我将if( !q_changed )
条件更改为while (!q_changed)
,以最大限度地缩短您在条件变量上重新等待的时间(如果虚假唤醒)(这也可以让您删除最后一个{{}} if (q_changed)
1}}条件块)。
答案 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);
}