Чтобы достигнуть поведения пассивного ожидания с использованием семафоров, вам нужно 2 переменные семафора вместо одной. Один для контроля чтения и один для контроля над письмом. Давайте назовем их:
sem_t read, write;
Внутри функции calc
вам нужно дождаться снятия блокировки чтения. sem_wait(&read);
и при выходе из функции calc
вам необходимо снять блокировку записи sem_post(&write);
, подробнее об этом позже.
В функции out
у вас будет обратный подход, вы получите дождитесь снятия блокировки записи sem_wait(&write);
и в конце вы снимите блокировку чтения sem_post(&read);
Теперь в main
вам нужно будет инициализировать оба семафора:
sem_init(&read, 0, 1);
sem_init(&write, 0, 0);
Обратите внимание, что я инициализировал read
значением 1 и write
значением 0. Причина в том, что sem_wait
проверит значение семафора, если оно больше 0, оно уменьшит значение и продолжит обработка. Поскольку мы хотим, чтобы функция calc
выполнялась до функции out
, мы инициализируем переменную read
1, чтобы она не ожидала первого нажатия и просто продолжала обработку.
Принимая во внимание, что в функции out
нам необходимо присвоить первые значения, прежде чем мы сможем их распечатать / обработать. Поэтому переменная write
инициализируется 0 и будет ждать, пока функция calc
не завершит sh и не увеличит write
с 0 до 1, вызвав sem_post(&write);
Вы можете инициализировать переменную read
с количеством создаваемых потоков, но в этом случае возникнет гоночная ситуация, и данные могут быть перезаписаны до того, как функция out
обработает их. Чтобы преодолеть эту ситуацию, вам нужно создать буфер для таких значений, как список или массив. Также дополнительный семафор для управления mutexlock, который будет вызываться после каждого sem_wait()
и перед каждым sem_post()
, чтобы не получить доступ к буферу значений одновременно.
Подробный пример с семафорами можно найти здесь