【问题标题】:Pthread lost signals / slow conditions?Pthread丢失信号/缓慢的情况?
【发布时间】:2011-03-24 14:58:44
【问题描述】:

我正在为一些小型作业(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 循环中等待。作业由以下代码行提交(在两个代码 sn-ps 中,我删除了用于等待两个作业完成的代码):

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

我做错了什么?

谢谢!

【问题讨论】:

    标签: c mutex conditional-statements pthreads


    【解决方案1】:

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

        /* 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);
    

    【讨论】:

    • 谢谢。我做了修改,但问题仍然是一样的。当互斥锁被另一个线程释放时,似乎在条件内的互斥锁处阻塞的线程没有足够快地得到通知。
    • @Lenz:嗯,是的 - 一方面,另一个进程可能必须跨内核迁移。如果您的作业非常快,那么您只需为队列提供一次超过 2 个等待作业!
    猜你喜欢
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多