Intereting Posts
Как я могу предотвратить дочерние процессы зомби? Установка тревоги в миллисекундах в C Обратная строка с указателями? Как правильно использовать va_list в последовательности вызовов функций оболочки? Использование Linux C выберите системный вызов для мониторинга файлов sys_readlink не работает EFAULT – альтернативный C передать указатель массива int как параметр в функцию Существуют ли различия между ANSI C и ISO C? Указатели в C (Передача адресов в функцию) Отходы в распределении памяти для локальных переменных Как преобразовать римские цифры в int при отказе от недопустимых чисел с помощью стандартного C? Как выделить массив перед вызовом strcpy? как вызвать функции C из процедур сборки и связать файлы C и сборки с помощью nasm и gcc Освобождение (vfree-ing) указателя на изменчивые данные Почему функция time (time_t *) возвращает и возвращает значение by-ref?

Захватывайте multithreading (pthread в Windows)

Надеюсь, ты сможешь помочь мне в моих проблемах. Моя программа делает то, что я действительно не понимаю. objective программы указана ниже: Создайте два streamа (task_timer и task_read). Эти streamи должны отображать на стандартном выходе (stdout) следующее сообщение: «Tache 1 Tache 2 Tache 1 Tache 2 …»

Код:

static void* task_timer(void* arg); static void* task_read(void* p); struct strShared{ pthread_mutex_t mut; pthread_mutex_t mut2; pthread_cond_t synchro; pthread_cond_t synchro2; }; struct strTimer{ int wt; strShared* psh; }; static void* task_timer(void* p){ time_t echeance; strTimer* timer; int time_waiting = 1000; time_t now; if(p != NULL){ timer = p; time_waiting = timer->wt; //ms echeance = time (NULL) + TIME_OF_THREAD; while (1) { pthread_mutex_lock(&timer->psh->mut); printf("Tache 1\n"); pthread_cond_signal(&timer->psh->synchro); pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut); pthread_mutex_unlock(&timer->psh->mut); } } return NULL; } static void* task_read(void* p){ strTimer* timer; if(p != NULL){ timer = p; while(1){ pthread_mutex_lock(&timer->psh->mut); pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut); printf("Tache 2\n"); pthread_cond_signal(&timer->psh->synchro2); pthread_mutex_unlock(&timer->psh->mut); } } return NULL; } int main (void) { pthread_t ttimer; pthread_t tread; /* TIMER */ strTimer timer; strShared shtimer; shtimer.mut = PTHREAD_MUTEX_INITIALIZER; shtimer.mut2 = PTHREAD_MUTEX_INITIALIZER; shtimer.synchro = PTHREAD_COND_INITIALIZER; shtimer.synchro2 = PTHREAD_COND_INITIALIZER; timer.psh = &shtimer; timer.wt = 1000; /* Threads */ pthread_create(&ttimer, NULL, task_timer, &timer); pthread_create(&tread, NULL, task_read, &timer); pthread_join(ttimer,NULL); pthread_join(tread,NULL); return 0; } 

По моему мнению, этот код является хорошим способом достижения этой цели. Тем не менее, он не работает, я думаю, я допустил некоторые ошибки. По моему мнению, он работает следующим образом:

  1. Оба streamа создаются и исполняются в паралелизме
  2. Task_read принимает мутекс-мут, дожидается синхронный сигнал и освобождает мьютекс, потому что сигнал никогда не прибывает
  3. Task_timer принимает мутекс-мут и отображает «Tache 1» на стандартном выходе
  4. Затем Task_timer отправляет сигнальную синхронизацию и ждет сигнала synchro2 (освобождает мьютекс, потому что сигнал никогда не прибывает)
  5. Task_read получает сигнальную синхронизацию и принимает мутекс-мут и отображает «Tache 2»,
  6. Task_read отправляет сигнал synchro2 и освобождает мутекс mutex и переходит к началу цикла While
  7. Task_timer получает сигнал synchro2 и освобождает мьютекс и переходит к началу цикла While

Однако этого не происходит. На самом деле, кажется, что программа застревает после отображения «Tache 1». Кто-то может объяснить мне, почему это происходит, пожалуйста? Думаю, я думаю, что плохо, но я хотел бы понять …

Большое спасибо, esc39

Если вы новичок в многопоточности, я предлагаю не использовать переменные условия. Вам не нужно использовать какую-либо переменную условия для описанной вами цели. Поэтому удалите строки pthread_cond_wait и pthread_cond_signal в обоих streamах.

Вместо этого вы можете просто добавить функцию сна после разблокировки мьютекса в каждом streamе. Например, task_read может быть изменен на:

 pthread_mutex_lock(&timer->psh->mut); printf("Tache 2\n"); pthread_mutex_unlock(&timer->psh->mut); usleep(10000); 

Посмотрим, что произойдет, когда task_timer получит блокировку.

 pthread_mutex_lock(&timer->psh->mut); /*acquires a lock*/ /*|*/ printf("Tache 1\n"); /*output*/ /*|*/ pthread_cond_signal(&timer->psh->synchro); /*sends a signal*/ /*|*/ /* no one is waiting for the signal on this cond, so the signal is ignored*/ pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut); /*releases lock and waits for signal*/ /*|*/ pthread_mutex_lock(&timer->psh->mut); /*acquires a lock*/ /*|*/ pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut); /*releases lock and waits for signal*/ /*|*/ /*|*/ /*|*/ /*|*/ printf("Tache 2\n"); /*never happens*/ pthread_mutex_unlock(&timer->psh->mut); /*never happens*/ /*|*/ pthread_cond_signal(&timer->psh->synchro2); /*|*/ pthread_mutex_unlock(&timer->psh->mut); 

Тупик.

Простой рецепт: поместите ваши вызовы pthread_cond_signal() за пределы критических разделов. Рассмотрим это как правило. Когда у вас есть пара или несколько streamов, синхронизирующихся с одним и тем же набором mutex / cond я едва ли могу представить себе сценарий, когда разумно сигнализировать из критического раздела. Семантика сигнала и трансляции похожа: эй, ребята, я закончил свою работу над критическими ресурсами, вы можете сразу следовать . Когда stream находится внутри критической секции, сигнализируя о cond он делает ложную инструкцию. Потому что это не сделано.

BTW, в вашем случае вам нужен дополнительный флаг, указывающий, какой stream должен выполняться. И вызывается pthread_cond_wait() только в том случае, если флаг указывает другой ход streamа.

Итак, основной алгоритм для каждого streamа будет (в псевдокоде):

 while(loop_again) { do_processing_on_non_critical_resources(); /* it's optional */ lock(mutex); while(not_my_turn) { /* explained later */ wait(cond,mutex); } do_processsing_on_critical_resources(); set_flag_to_other_thread(); unlock(mutex); signal(cond); do_processing_on_non_critical_resources(); /* it's optional */ } 

Проверка not_my_turn выполняется в цикле while, а не простой, if проверка, потому что, согласно документации, может быть ложное пробуждение из pthread_cond_timedwait() или pthread_cond_wait() :

При использовании переменных условия всегда существует логический предикат, включающий общие переменные, связанные с каждым условием ожидания, который является истинным, если stream должен продолжаться. Могут возникнуть побочные пробуждения из функций pthread_cond_timedwait() или pthread_cond_wait() . Поскольку возврат из pthread_cond_timedwait() или pthread_cond_wait() не означает ничего о значении этого предиката, предикат должен быть переоценен при таком возврате.

Итак, выше вы имеете общий случай синхронизированной нити. Однако для вашего случая ответ от M.KHd является правильным и достаточным.