Тезис о том, что потоки производителя и потребителя чередуются BUFFER_SIZE
раз, неверен. Программа здесь демонстрирует недетерминированность, поэтому возможен один из многих заказов между производителем и потребителем. То, как написана программа, гарантирует только две вещи:
- Если потребитель получает блокировку, когда буфер пуст, он снимет sh блокировку и будет ждать, пока производитель сообщит о ней.
- Если производитель получит блокировку при заполнении буфера, он снимет блокировку sh и будет ждать сигнала от потребителя.
Как следствие этих двух свойств Гарантируется, что производитель всегда будет излучать первым, а потребитель всегда будет последним из двух потоков для печати. Это также гарантирует, что ни один из потоков не сможет успешно запросить блокировку более чем BUFFER_SIZE
раз подряд.
Помимо двух вышеупомянутых гарантий, фактический запуск даст полностью результаты, определенные узлом c. Случилось так, что ваша операционная система произвольно решила повторно запланировать последний поток в ваших наблюдаемых запусках. Это разумно, потому что ваша программа сказала планировщику: «делайте все, что хотите, в пределах ограничений порядка двух правил». ОС может свободно смещаться в сторону планирования того же потока для повторного запуска на ЦП, если она того пожелает; на самом деле, это, вероятно, наиболее целесообразно, поскольку поток, только что запущенный на ЦП, уже загрузил свои ресурсы ( локальность ссылки ), поэтому накладные расходы от переключений контекста уменьшаются.
Несмотря на то, что ОС может планировать один и тот же поток несколько раз, также возможно, что, например, весь процесс отменен по расписанию и запущен процесс с более высоким приоритетом, потенциально высвобождая рабочий набор из первый процесс. В этом сценарии, когда первый процесс перепланирован, любой поток может быть так же хорош, как и план.
В любом случае, когда программист допускает недетерминированность, упорядочение выходит за пределы допустимого. hands и могут показаться не случайными по ряду сложных причин.
Как я упоминал в комментариях, важно иметь возможность убедиться в свойствах упорядочения программы, не запуская программа. Запуск программы может доказать, что недетерминизм существует, но он не может доказать, что программа детерминирована c. Некоторые многопоточные программы содержат незначительные ошибки планирования или состояния гонки, которые могут возникать только один раз за триллион (или больше!) Запусков, поэтому нет возможности вручную проверить такие недетерминированные c программы. К счастью, этот тривиален, поэтому его легко запустить до появления недетерминизма.
Полезный инструмент для отладки многопоточных программ - sleep(1)
в unistd.h
. Эта функция вызывает отмену планирования вызывающего потока, нарушая естественное упорядочение программы и вызывая определенное упорядочение. Это может помочь вам доказать заказ недвижимости. Например, добавление sleep(1)
после pthread_cond_signal(&emptyCond);
показывает, что при данной возможности потребитель захватит блокировку до того, как в вашей программе произойдет BUFFER_SIZE
.
Для сложных программ такие инструменты, как Cuzz существует для программной вставки sleep
вызовов для выявления ошибок в заказе. См. подход к тестированию для многопоточного программного обеспечения для разнообразия ресурсов и стратегий.