Очевидная вещь - взять блокировку перед вызовом pthread_cancel
и удерживать такую же блокировку в вашем «безопасном регионе».
К сожалению, вы не можете ждать мьютекса или семафора в обработчике сигналов. Но сигналы тревоги - не единственный способ сделать что-то через 10 секунд - вместо этого вы можете перевести основной поток в режим сна на 10 секунд, а затем проснуться, снять блокировку, отменить рабочий поток и затем присоединиться к нему.
Конечно, это будет означать, что основной поток будет спать 10 секунд, даже если рабочий поток завершит работу через 5 секунд. Поэтому вместо того, чтобы спать, основной поток должен сделать 10-секундное время ожидания для семафора, который рабочий поток публикует после завершения.
Как и во сне, таймерное ожидание может завершиться рано из-за сигнала, поэтому обязательно повторите таймерное ожидание на EINTR. Ваши существенные случаи: EINTR (снова ждать), успех (присоединиться к рабочему потоку - нет необходимости отменять, поскольку он опубликовал семафор), ETIMEDOUT (снять блокировку, отменить, объединить) и, если хотите, другие ошибки. Однако для sem_timedwait
нет других ошибок, которые могут повлиять на вас.
Другая идея состоит в том, чтобы блокировать SIGALRM в вашем «безопасном регионе», что было бы проще, за исключением того, что (а) я никогда не могу вспомнить, как безопасно выполнять ввод-вывод с отключенными сигналами, и (б) ваш рабочий поток, вероятно, мог бы быть запуск «одновременно» с обработчиком сигнала (либо действительно одновременным, либо, очевидно, таковым из-за упреждения), что означает, что сигнал может быть принят, затем ваш работник отключает сигналы и входит в критическую область, затем обработчик сигналов отменяет его. Если никто не отвечает, кто на самом деле может запомнить детали, вот некоторая информация о блокирующих сигналах .