Я пишу простой пул потоков для некоторых небольших работ (от 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
Что я делаю не так?
Спасибо!