Pthread потерял сигналы / медленные условия? - PullRequest
3 голосов
/ 03 августа 2010

Я пишу простой пул потоков для некоторых небольших работ (от 100 до 700 микросекунд). Я работаю только с двумя потоками (потому что есть только две работы, а процессор имеет только два ядра). Моя проблема в том, что большую часть времени обе работы выполняются одним и тем же потоком. Проблема не возникает с большими заданиями (несколько миллисекунд).

Ожидаемое поведение будет (в этом случае ускорение будет таким, как ожидалось:

  • Тема 1 после cond_wait
  • Работа выполнена: 1
  • Тема 0 после cond_wait
  • Задание выполнено: 0
  • Тема 1 до cond_wait
  • Тема 0 перед cond_wait

Но иногда (50%) (другой поток заблокирован, прежде чем мьютекс в cond не будет уведомлен?):

  • Тема 1 после cond_wait
  • Работа выполнена: 1
  • Работа выполнена: 1
  • Тема 0 после cond_wait
  • Тема 0 перед cond_wait
  • Тема 1 до cond_wait

Или еще хуже (сигнал для другого потока потерян?):

  • Тема 0 после cond_wait
  • Задание выполнено: 0
  • Задание выполнено: 0
  • Тема 0 перед cond_wait

Это основной цикл, выполняемый обоими потоками (созданный с помощью 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);
    }
}

Перед отправкой заданий оба потока ждут в цикле while при условии workcv. Задания представляются в следующих строках кода (в обоих фрагментах кода я удалил код, используемый для ожидания завершения обоих заданий):

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 Ответ

1 голос
/ 03 августа 2010

Вместо 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);
...