Вы неправильно используете переменные условия. Как указывает справочная страница Linux для pthread_cond_wait()
:
При использовании условных переменных всегда существует логический предикат, включающий общие переменные, связанные с каждым условным ожиданием, которое является истинным если поток должен продолжить. Могут возникнуть ложные пробуждения от функций pthread_cond_timedwait()
или pthread_cond_wait()
. Поскольку возврат из pthread_cond_timedwait()
или pthread_cond_wait()
не подразумевает ничего о значении этого предиката, предикат должен быть повторно оценен после такого возврата.
Это означает, что он не подходит для поток для интерпретации возврата из pthread_cond_wait()
как признака того, что он должен продолжаться. Вместо этого он должен интерпретировать такой возврат как признак того, что он должен проверить некоторое условие, включающее одну или несколько общих переменных, чтобы определить, следует ли продолжить. Если условие не выполняется, то обычно следует подождать еще немного. Также обычно уместно проверить условие перед первым ожиданием, чтобы не пропустить сигнал.
Конечно, все обращения к общей переменной должны выполняться под защитой одного и того же мьютекса, по крайней мере, если любая из них может быть записана.
На принимающей стороне все выглядит примерно так:
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
_Bool should_proceed1 = 0;
void *thread1(void *arg) {
pthread_mutex_lock(&lock1);
while (!should_proceed1) {
pthread_cond_wait(&cond1, &lock1);
}
pthread_mutex_unlock(&lock1);
// ...
}
На стороне сигнализации это может выглядеть так:
pthread_mutex_lock(&lock1);
should_proceed1 = 1;
pthread_mutex_unlock(&lock1);
pthread_cond_signal(&cond1);
Обратите внимание, что общая переменная should_proceed1
доступна под защитой одного и того же мьютекса в обоих местах, и что это также мьютекс, который ожидающий поток связывает с CV для своего ожидания. Кроме того, вызов pthread_cond_signal()
может происходить и в защищенной мьютексом области - вам не нужно сначала разблокировать мьютекс - но, хотя ожидающий поток сразу же активируется (если он есть), он не будет продолжаться пока он не сможет вернуть мьютекс.