У меня есть программа, которая блокируется, когда один из потоков вызывает pthread_cond_siganl
(или трансляцию).Проблема воспроизводима на 100% в основной программе.Я не мог понять, что с ним не так, и, таким образом, извлек фрагмент кода, который вызывает и сигнал вызывается.Однако тупик не может быть воспроизведен с извлеченной проблемой .
Запуск valgrind
в основной программе не сообщает о недопустимых операциях чтения / записи или утечек памяти.
Я хочу знать, каковы возможные причины тупика при вызове pthread_cond_signal
.
Извлеченный фрагмент следует.
#include <pthread.h>
#include <math.h>
#include <syscall.h>
#include <assert.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
void Task() {
cerr << syscall(SYS_gettid) << " In Task, sleeping..." << endl;
sleep(5);
}
pthread_mutex_t lock;
pthread_cond_t cond;
bool doingTheTask= false;
void* func(void* ) {
pthread_mutex_lock(&lock);
if (doingTheTask) {
cerr << syscall(SYS_gettid) << " wait... " << endl;
while ( doingTheTask) {//spurious wake-up
cerr << syscall(SYS_gettid) << " waiting..." << endl ;
pthread_cond_wait(&cond, &lock);
cerr << syscall(SYS_gettid) << " woke up!!!" << endl ;
}
}
else {
cerr << syscall(SYS_gettid) << " My Turn to do the task..." << endl;
assert( ! doingTheTask );
doingTheTask= true;
pthread_mutex_unlock(&lock);
Task();
cerr << syscall(SYS_gettid) << " Before trying to acquire lock" << endl;
pthread_mutex_lock(&lock);
cerr << syscall(SYS_gettid) << " After acquiring lock" << endl ;
assert( doingTheTask );
doingTheTask = false;
cerr << syscall(SYS_gettid) << " Before broadcast" << endl;
pthread_cond_broadcast(&cond);
cerr << syscall(SYS_gettid) << " After broadcast" << endl;
}
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_mutex_init(&lock,NULL);
pthread_cond_init(&cond,NULL);
pthread_t thread[2];
for ( int i = 0 ; i < 2 ; i ++ ) {
if (0 != pthread_create(&thread[i], NULL, func, NULL) ) {
cerr << syscall(SYS_gettid) << " Error creating thread" << endl;
exit(1);
}
}
for ( int i = 0 ; i < 2 ; i ++ ) {
pthread_join(thread[i],NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
Единственная важная часть - это функция func.Остальные части просто представлены для компиляции.
Как я уже говорил, проблема не воспроизводима в этой программе .Разница между этим фрагментом и основной программой:
- В основной программе
mutex
и condvar
являются полями-членами, а функция - методом-членом. - Задача выполняет какую-то задачу вместо сна.
- Несколько потоков могут ждать, и мы должны передавать, а не сигнализировать.Однако взаимоблокировка воспроизводима на 100%, даже когда я использую сигнал и один ожидающий поток.
Проблема, которую я пытаюсь решить с помощью этого фрагмента кода, - это механизм, который выполняет задачу один раз, когда, по крайней мере,это нужно сделать одному из потоков.Но никакие два потока не должны выполнять задачу параллельно, и как только один из них выполняет задачу, другим не нужно это делать.Клиенты этого метода предполагают, что он блокируется до тех пор, пока задача не будет выполнена (поэтому я не могу сразу же вернуться, увидев, что кто-то выполняет задачу).
Обратные следы заблокированных потоков:
#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136
#1 0x00007ffff73e291c in pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:259
и
#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136
#1 0x00007ffff73e30b1 in pthread_cond_signal@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S:142
pthread_cond_signal deadlocks является аналогичной проблемой.Но похоже, что один из вопросов был повреждением памяти.У меня нет повреждения памяти (говорит valgrind
).
Проблема воспроизводится на 100% на двух машинах, на которых я ее тестировал.(Последняя версия ArchLinux и Uubntu 10.04.3).
Ниже приведен пример вывода основной программы.Это снова показывает, что потоки блокируются перед вызовом pthread_cond_wait
и pthread_cond_signal
.(В первом столбце показаны идентификаторы потоков).
3967 In Task, sleeping...
3967 My Turn to do the task...
3967 In Task, sleeping...
3973 wait...
3973 waiting...
3976 <output from some other thread>
3967 Before trying to acquire lock
3967 After acquiring lock
3967 Before broadcast
Основная программа на C ++.Но я использую части языка C и поэтому избегаю использования тега C ++.