Ну, что же, execution path действительно расставил все на свои места...
В данном случае потеря сигнала несущественна.
Формально я спор проиграл, шлите реквизиты/способы оплаты.
Отправил личным сообщением.
Но по сути все равно остаются вопросы о целесообразности выноса сигнала за критическую секцию, ...
Ну как же! Известно, что чем меньше времени занята критическая секция, тем больше свободы для потоков и тем больше потенциальный параллелизм их исполнения. Сигнализирование кондвара - не элементарная операция. Это вход в ядро с неизвестно какой кучей кода внутри и с потенциальной блокировкой, если ядро занято другим потоком (для SMP). Во всяком случае кода там внутри ядра исполнится явно больше, чем в самих функциях производителя и потребителя целиком.
...плюс вторая оптимизация - о ней ничего не известно.
Вторая оптимизация состоит в том, что нет надобности сигналить кондвар каждый раз, ибо если список не был полон, то производители не могли быть заблокированными, а если список не был пуст, то не могли быть заблокированы потребители (во всяком случае, не больше их, чем сейчас есть свободных ячеек для первых или зянятых - для вторых). Таким образом, сигнализоворать кондвар можно лишь в граничных случаях. Но тут есть одна тонкость! Если не вынносить pthread_cond_signal за критическую секцию, то его можно так и оставить, а если выносить - его уже надо менять на pthread_cond_broadcast. Тоесть, с обеими оптимизациями функции приобретают следующий вид.
void producer(buffer_t *b, char item)
{
int was_empty;
pthread_mutex_lock(&b->mutex);
while (b->occupied >= BSIZE)
pthread_cond_wait(&b->less, &b->mutex);
assert(b->occupied < BSIZE);
b->buf[b->nextin++] = item;
b->nextin %= BSIZE;
was_empty = b->occupied++ == 0;
pthread_mutex_unlock(&b->mutex);
if (was_empty)
pthread_cond_broadcast(&b->more);
}
и
char consumer(buffer_t *b)
{
char item;
int was_full;
pthread_mutex_lock(&b->mutex);
while(b->occupied <= 0)
pthread_cond_wait(&b->more, &b->mutex);
assert(b->occupied > 0);
item = b->buf[b->nextout++];
b->nextout %= BSIZE;
was_full = b->occupied-- == BSIZE;
pthread_mutex_unlock(&b->mutex);
if (was_full)
pthread_cond_broadcast(&b->less);
return item;
}
P.S. Оптимизация выглядит достаточно подозрительно опасно - я даже сам-вот сейчас засомневался и долго проверял в уме - но должно быть всё нормально.