Обычно я рекомендую держать вызов pthread_cond_signal()
в заблокированном регионе, но, вероятно, не по тем причинам, о которых вы думаете.
В большинстве случаев не имеет значения, звоните ли вы pthread_cond_signal()
с заблокированной блокировкой или нет. Бен прав, что некоторые планировщики могут принудительно переключать контекст при снятии блокировки, если другой поток ожидает, поэтому ваш поток может быть отключен до того, как сможет вызвать pthread_cond_signal()
. С другой стороны, некоторые планировщики будут запускать ожидающий поток, как только вы вызовете pthread_cond_signal()
, поэтому, если вы вызываете его с удерживаемой блокировкой, ожидающий поток проснется и затем вернется обратно в спящий режим (потому что теперь он заблокирован на мьютекс), пока сигнальный поток не разблокирует его. Точное поведение сильно зависит от реализации и может меняться в зависимости от версии операционной системы, поэтому на это нельзя полагаться.
Но все это выходит за рамки того, что должно быть вашей главной задачей, а именно читаемость и правильность вашего кода. Вы вряд ли увидите какую-либо реальную выгоду в производительности от такого рода микрооптимизации (помните первое правило оптимизации: сначала профиль, сначала оптимизируйте). Тем не менее, проще думать о потоке управления, если вы знаете, что набор ожидающих потоков не может измениться между точкой, в которой вы задали условие и отправили сигнал. В противном случае вам придется подумать о таких вещах, как «что если поток A устанавливает testCondition=TRUE
и снимает блокировку, а затем поток B запускается и видит, что testCondition
имеет значение true, поэтому он пропускает pthread_cond_wait()
и переходит к сбросу testCondition
до FALSE
, а затем, наконец, поток A запускается и вызывает pthread_cond_signal()
, который пробуждает поток C, потому что поток B фактически не ожидал, но testCondition
больше не соответствует действительности ". Это сбивает с толку и может привести к трудно диагностируемым состояниям гонки в вашем коде. По этой причине я думаю, что лучше сигнализировать с удерживаемой блокировкой; таким образом, вы знаете, что установка условия и отправка сигнала являются атомарными по отношению друг к другу.
На связанной ноте способ, которым вы звоните pthread_cond_wait()
, неверен. Возможно (хотя и редко) для pthread_cond_wait()
возврата без фактической сигнализации переменной условия, и есть другие случаи (например, гонка, которую я описал выше), когда сигнал может закончить пробуждение потока, даже если условие не ' правда. Чтобы быть в безопасности, вам нужно поместить вызов pthread_cond_wait()
в цикл while()
, который проверяет условие, так что вы перезвоните в pthread_cond_wait()
, если условие не выполнено после того, как вы снова получите блокировку. В вашем примере это будет выглядеть так:
pthread_mutex_lock(&my_lock);
while ( false == testCondition ) {
pthread_cond_wait(&my_wait,&my_lock);
}
pthread_mutex_unlock(&my_lock);
(Я также исправил то, что, возможно, было опечаткой в вашем исходном примере, а именно my_mutex
для вызова pthread_cond_wait()
вместо my_lock
.)