全局变量在线程中没有变化?

时间:2018-05-29 20:39:10

标签: c pthreads

我试图更新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;
}

1 个答案:

答案 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 搞砸了,并且可能非常难以检测边缘情况做了(搞砸了,就是这样)。小心。这个具体的例子是一系列职责,而不是同时履行职责,使其相当微不足道,所以我很乐于展示它。

希望它有所帮助。

相关问题