- все ли потоки используют одну и ту же переменную c и mtx?
Да, как и любая другая глобальная переменная. Вы можете распечатать их адреса из каждого потока, чтобы подтвердить это.
- необходимо ли при возврате pthread_cond_wait проверить, действительно ли выполнено какое-либо условие?
Да, все интерфейсы ожидания подвержены ложным пробуждениям, и вы всегда отвечаете за проверку своего собственного предиката. См. документацию или хорошую книгу.
- программа в настоящее время не завершает работу ...
pthread_cancel
одинаково ужасен и никогда не должен использоваться. Это действительно трудно понять правильно. Если вы хотите сообщить своему потоку о выходе, напишите механизм уведомления - встроите его в существующий цикл предикатов - и выполните сигнал / трансляцию, чтобы все потоки проснулись и осознали, что пришло время умирать.
Относительно выхода отложено: thread_id [0] завершается нормально, и я застрял в строке pthread_join (thread_id [1], NULL) ;, он говорит (Выход), но, кажется, застрял в блокировке
Одна из самых сложных вещей в pthread_cancel
- это cleanup . Если отмена происходит во время удержания блокировки, вам нужно использовать pthread_cleanup_push
для эмуляции совместимой с отменой семантики RAII. В противном случае первый поток может (и в этом случае умер) с заблокированным мьютексом.
В этом случае второй поток пытается выйти из pthread_const_wait
из-за отмены, но он должен восстановить блокировку и не может.
Обычная форма цикла условной переменной такова (и хороший справочник должен показывать нечто подобное):
void *thread(void *data)
{
struct Args *args = (struct Args *)data;
/* this lock protects both the exit and work predicates.
* It should probably be part of your argument struct,
* globals are not recommended.
* Error handling omitted for brevity,
* but you should really check the return values.
*/
pthread_mutex_lock(&args->mutex);
while (!exit_predicate(args)) {
while (!work_predicate(args)) {
/* check the return value here too */
pthread_cond_wait(&args->condition, &args->mutex);
}
/* work_predicate() is true and we have the lock */
do_work(args);
}
/* unlock (explicitly) only once.
* If you need to cope with cancellation, you do need
* pthread_cleanup_push/pop instead.
*/
pthread_mutex_unlock(&args->mutex);
return data;
}
, где ваш код может просто войти в bool exit_predicate(struct Args*)
, bool work_predicate(struct Args*)
и void do_work(struct Args*)
. Сама структура петли редко нуждается в значительных изменениях.