我试图更新main函数中的全局变量,并让一个线程告诉我这个变量是否为正数。
代码:https://pastebin.com/r4DUHaUV
当我运行它时,只有2出现,但1和2应该是正确答案。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_t tid;
pthread_mutex_t mtx;
pthread_cond_t cond;
int nr=0;
void* function(void* arg)
{
pthread_mutex_lock(&mtx);
printf("Number in thread : %d \n",nr);
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
}
int main()
{
pthread_mutex_init(&mtx,NULL);
pthread_create(&tid,NULL,function,NULL);
int i;
for(i=0;i<3;i++)
{
int isPos=0;
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
if(nr>0)
isPos=1;
if(isPos==1)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
}
pthread_join(tid,NULL);
return 0;
}
答案 0 :(得分:3)
正如我在一般性评论中所提到的,我将在此重复:
无法保证主线程不会被锁定,锁定互斥锁, 改变nr,发信号通知cv(无论是否有人 在子线程之前,等待它,并解锁互斥锁 甚至锁定互斥锁,更不用说开始等待简历了。在那里面 case,当孩子最终得到互斥锁时,nr可以是1(或2等)。 这意味着你的while循环将被跳过(nr&lt; = 0不是真的),并且 无论当前的nr值是什么,都将在出路上打印出来。 我已经运行了好几次,得到了1x1,1x2和2x2,多个 次。
对此的一个简单修复涉及使用您已设置的cv / mtx对来监控来自main
的更改,以便还监控function
的启动 - 启动。首先是代码:
守则
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int nr = -1;
void* function(void* arg)
{
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
// now start waiting (which will unlock the mutex as well, which means
// the main thread will be be able to acquire it and check nr safely
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
// now we know the child is ready to receive signals
int i;
for(i=0;i<3;i++)
{
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
int isPos = (nr>0);
pthread_mutex_unlock(&mtx);
if (isPos)
pthread_cond_signal(&cond);
}
pthread_join(tid,NULL);
return 0;
}
如何运作
nr
的初始值确定为-1
。只有子线程会直接将其更改为0
,即使只是在谓词互斥锁的保护下。
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
请注意,在上述三行之后,子仍然拥有互斥锁。它以原子方式释放它并且开始等待第一个进入后续循环的通知:
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
现在,回到main
,启动创建子线程,获取互斥锁,然后监视直到nr
为零。
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
实现此目标的唯一方法是nr == 0
。当发生这种情况时,孩子必须更改它,但更重要的是,它也必须等待条件变量(这就是我们获取互斥锁的方式;还记得吗?)从那时起,代码就类似了。值得注意的是,我使用pthread初始化器确保互斥锁和cvar正确站立。您的原始帖子缺少cvar初始化。
最后,使用单个cvar-mtx对执行多谓词双重任务是 easy 搞砸了,并且可能非常难以检测边缘情况做了(搞砸了,就是这样)。小心。这个具体的例子是一系列职责,而不是同时履行职责,使其相当微不足道,所以我很乐于展示它。
希望它有所帮助。