Pthread丢失信号/慢速条件?

时间:2010-08-03 08:52:15

标签: c mutex conditional-statements pthreads

我正在为一些小作业(100到700微秒)编写一个简单的线程池。我只使用两个线程(因为只有两个作业,处理器只有两个核心)。我的问题是大多数时候两个作业都是由同一个线程执行的。较大的作业(几毫秒)不会出现此问题。

预期的行为是(在这种情况下,加速是预期的:

  • cond_wait
  • 之后的线程1
  • 工作执行人:1
  • cond_wait
  • 之后的线程0
  • 作业执行:0
  • cond_wait之前的线程1
  • cond_wait
  • 之前的线程0

但有时(50%)(其他线程在cond中的互斥锁被阻止之前被阻止通知?):

  • cond_wait
  • 之后的线程1
  • 工作执行人:1
  • 工作执行人:1
  • cond_wait
  • 之后的线程0
  • cond_wait
  • 之前的线程0
  • cond_wait之前的线程1

或更糟糕的是(其他线程丢失的信号?):

  • cond_wait
  • 之后的线程0
  • 作业执行:0
  • 作业执行:0
  • cond_wait
  • 之前的线程0

这是两个线程执行的主循环(使用pthread_create创建):

pthread_mutex_lock(&pl->mutex);
for (;;) {
    /* wait on notification that a new job is available */
    while (pl->queue_head==NULL) {
        //printf("Thread %d before cond_wait\n",threadID);
        pthread_cond_wait(&pl->workcv, &pl->mutex);
        //printf("Thread %d after cond_wait\n",threadID);
    }
    /* get first job */
    job=pl->queue_head;
    if (job!=NULL) {
        /* remove job from the queue */
        pl->queue_head=job->next;
        if (job==pl->queue_tail){ 
            pl->queue_tail=NULL; 
        }
        pthread_mutex_unlock(&pl->mutex);
        /* get job parameter */
        func=job->func;
        arg=job->arg;
        /* Execute job */
        //printf("Job executed by: %d\n",threadID);
        func(arg, threadID);
        /* acquire lock */
        pthread_mutex_lock(&pl->mutex);
    }
}

在提交作业之前,两个线程都在workcv条件下等待while循环。作业由以下代码行提交(在两个代码片段中,我删除了用于等待两个作业完成的代码):

pthread_mutex_lock(&pl->mutex);
/* Append job to queue */
if (pl->queue_head==NULL) {
    pl->queue_head=job[numJobs-1];
}else {
    pl->queue_tail->next=job[numJobs-1];
}
pl->queue_tail=job[0];
/* Wake up thread if one is idle */
pthread_cond_broadcast(&pl->workcv);
pthread_mutex_unlock(&pl->mutex);

使用互斥锁,线程和条件的默认属性。 环境:Gcc 4.2.1,Mac OSX Snow Leopard

我做错了什么?

谢谢!

1 个答案:

答案 0 :(得分:1)

而不是pthread_cond_broadcast(),您应该使用pthread_cond_signal()。此外,在线程完成一项工作后,它应该发出条件变量信号:

    /* remove job from the queue */
    pl->queue_head=job->next;
    if (job==pl->queue_tail){ 
        pl->queue_tail=NULL; 
    }
    if (pl->queue_head != NULL)
        pthread_cond_signal(&pl->workcv);
    pthread_mutex_unlock(&pl->mutex);