Ответ 1
Правильно, что отмененные потоки не разблокируют мьютексы, которые они хранят, вам нужно устроить это вручную, что может быть сложно, так как вам нужно очень осторожно использовать правильные обработчики очистки вокруг каждой возможной точки отмены. Предполагая, что вы используете pthread_cancel
, чтобы отменить поток и установить обработчики очистки с помощью pthread_cleanup_push
, чтобы разблокировать мьютексы, есть несколько альтернатив, которые вы могли бы попробовать, которые могли бы быть проще, и, следовательно, могут быть более надежными.
Использование RAII для разблокировки мьютекса будет более надежным. В GNU/Linux pthread_cancel
реализовано специальное исключение типа __cxxabi::__forced_unwind
, поэтому, когда поток отменяется, генерируется исключение, и стек разматывается. Если мьютекс заблокирован по типу RAII, то его деструктор будет гарантированно выполняться, если стек разматывается с помощью исключения __forced_unwind
. Boost Thread
предоставляет переносимую библиотеку С++, которая обертывает Pthreads и намного проще в использовании. Он предоставляет тип RAII boost::mutex
и другие полезные абстракции. Boost Thread также предоставляет свой механизм "прерывания потока", который похож на отмену Pthread, но не то же самое, а точки отмены Pthread (например, connect
) не являются точками прерывания потока Boost, что может быть полезно для некоторых приложений. Однако в случае вашего клиента с момента отмены прерывания вызова connect
они, вероятно, хотят придерживаться отмены Pthread. (Не переносной) способ GNU/Linux реализует отмену как исключение, он будет хорошо работать с boost::mutex
.
На самом деле нет оправдания явно блокировки и разблокировки мьютексов, когда вы пишете на С++, IMHO самая важная и самая полезная функция С++ - это деструкторы, которые идеально подходят для автоматического выпуска ресурсов, таких как блокировки мьютекса.
Другим вариантом будет использование надежного мьютекса, который создается путем вызова pthread_mutexattr_setrobust
на pthread_mutexattr_t
перед инициализацией мьютекса. Если нить умирает при сохранении надежного мьютекса, ядро его запомнит, так что следующий поток, который пытается заблокировать мьютекс, получает специальный код ошибки EOWNERDEAD
. Если возможно, новый поток может снова защитить данные, защищенные потоком, и взять на себя ответственность за мьютекс. Это гораздо труднее использовать правильно, чем просто использовать тип RAII для блокировки и разблокировки мьютекса.
Совершенно другой подход состоял бы в том, чтобы решить, действительно ли вам нужно удерживать блокировку мьютекса при вызове connect
. Удержание мьютексов во время медленных операций - это не очень хорошая идея. Не можете ли вы позвонить connect
, а затем, если удалите блокировку мьютекса и обновите защищенные общедоступные данные с помощью мьютекса?
Мое предпочтение было бы в том, чтобы использовать Boost Thread и избегать удержания мьютекса в течение длительных периодов времени.