如何使用pthread_cond_signal和pthread_cond_wait正确地使pthreads worker?

时间:2012-01-23 00:36:15

标签: c pthreads

尝试实现两个并行工作程序。在形成数据之后,我需要告诉工人获取数据并进行处理。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *worker(void *data);

struct worker_data_t
{
    pthread_t thread_id;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    long id, data;
};

struct worker_data_t *workers_data;

int main(int argc, char **argv)
{
    int cpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (cpus < 1)
        cpus = 1;

    workers_data = (struct worker_data_t *)malloc(cpus * sizeof(struct worker_data_t));
    int ret_val[cpus];

    for (int i = 0; i < cpus; i++)
    {
        pthread_mutex_init(&workers_data[i].mutex, NULL);
        pthread_cond_init(&workers_data[i].cond, NULL);
        workers_data[i].id = i;
    }

    for (int i = 0; i < cpus; i++)
        ret_val[i] = pthread_create(&workers_data[i].thread_id, NULL, worker, &workers_data[i]);

    pthread_mutex_lock(&workers_data[0].mutex);
    pthread_cond_signal(&workers_data[0].cond);
    pthread_mutex_unlock(&workers_data[0].mutex);

    pthread_mutex_lock(&workers_data[0].mutex);
    pthread_cond_signal(&workers_data[0].cond);
    pthread_mutex_unlock(&workers_data[0].mutex);

    for (int i = 0; i < cpus; i++)
        pthread_join(workers_data[i].thread_id, NULL);

    return 0;
}

void *worker(void *data)
{
    struct worker_data_t d = *((struct worker_data_t*)(data));
    printf("Thread %d started\n", d.id);
    for (;;)
    {
        pthread_mutex_lock(&workers_data[d.id].mutex);
        pthread_cond_wait(&workers_data[d.id].cond, &workers_data[d.id].mutex);
        printf("catch!\n");
        pthread_mutex_unlock(&workers_data[d.id].mutex);
    }
}

通过pthread_cond_signal通知工人后没有任何反应。如果我在每个pthread_cond_signal块之前放入sleep(1),它就会起作用。

如何让它在没有睡眠的情况下工作?

2 个答案:

答案 0 :(得分:2)

正如R.所说,并且他应该做出回答,你需要的是一个谓词。这是您测试以查看条件是否为真的内容。

在您的情况下,它应该是一个简单的变量,受workers_data[0].mutex保护。

然后在您的工作人员中,锁定互斥锁,就像您已经做的那样,然后检查谓词。如果谓词为真,则无需等待条件,所以不要。只需去做你需要做的事。如果谓词为假,则等待条件。

不要忘记的一个非常重要的一点是,谓词绝不能在条件变量使用的互斥锁之外进行更改。如果是的话,在某些情况下会错过这种情况,这会导致线程卡住。

答案 1 :(得分:1)

当该调用引用的condvar上没有锁定线程时,pthread_cond_signal()生成的信号将丢失。以下情况极有可能发生:

  1. main()线程调用pthread_create()
  2. main()线程执行1个或多个lock-signal-unlock blocks
  3. 子线程获得处理器时间并被pthread_cond_wait()锁定。信号已经丢失,因此永远不会被唤醒
  4. 如果线程在调用pthread_create()后立即获得CPU,则未定义。当您在发出信号之前执行sleep(1)时,您可以让工作线程执行并开始收听他们的信号。这是解决问题的方法之一。您仍然可能希望实现某种就绪检查以确保工作人员正在等待并且您的信号不会丢失(创建另一个condvar并在工作人员准备就绪时发出信号)。另一种方法是使用信号量。

    另外请记住,pthread_join()永远不会在您的程序中返回,因为工作人员无法离开无限循环。建议检查每个pthread_...()返回错误,特别是当您调查某种意外的程序行为时。