Как-то неправильно использовать мьютекс в C ++ - PullRequest
3 голосов
/ 20 июля 2011

У меня есть следующий код, чтобы попытаться (и не удалось) защитить критическую область в моем коде.По сути, я хочу, чтобы оператор печати был полностью выполнен любым потоком, прежде чем какой-либо другой поток напечатает другой оператор.

В main.h:

pthread_mutex_t printer_mutex;

В main.c - первое, чтоПрограмма делает:

pthread_mutex_init(&printer_mutex, NULL);

Потоки создаются следующим образом (хотя я удалил некоторые проверки):

for(long t = 0; t < NUM_THREADS; t++) {
   args[t].fw = fw;
   args[t].deriv_init = deriv_init;
   args[t].to_prove = fw.to_prove.at(i);
   pthread_create(&threads[t], NULL, do_derivation_helper, (void *) &args[t]);
}
for(long t = 0; t < NUM_THREADS; t++) {
  pthread_join(threads[t], NULL);
}

Затем в моем классе, который выполняет всю печатьв программе у меня есть следующее.Печать должна быть заблокирована, а затем разблокирована, когда она будет завершена.

void InfoViewer::rule_x_fires() {
    // START CRITICAL REGION
    pthread_mutex_lock(&printer_mutex);
    cout << "INFO: Rule x fires" << endl;
    pthread_mutex_unlock(&printer_mutex);
    // END CRITICAL REGION
}

Нежелательный вывод, который я получаю:

INFO: Rule x firesINFO: Rule x fires

Т.е. строка не закончена до того, как какой-то другой поток начинает печатать.

Есть идеи?Я не правильно инициализирую?Я в порядке, используя стандартные темы стиля C в моей программе C ++?

Ответы [ 3 ]

8 голосов
/ 20 июля 2011

Я полагаю, что проблема в определении переменной мьютекса в заголовочном файле. Таким образом, каждый модуль компиляции получает собственную версию такой переменной, и вы просто блокируете разные мьютексы. Просто сделайте это:

// .h header file: declare
extern pthread_mutex_t printer_mutex;

// one of the .c/.cpp files: define
pthread_mutex_t printer_mutex;

Редактировать 0:

Чтобы объяснить, почему он «работает» с несколькими определениями - мьютекс PThread можно инициализировать двумя различными способами - динамически с pthread_mutex_init и статически с PTHREAD_MUTEX_INITIALIZER. Изучив pthread.h, можно найти следующее (32-битная версия):

# define PTHREAD_MUTEX_INITIALIZER \
    { { 0, 0, 0, 0, 0, { 0 } } }

Это означает, что любая статическая переменная типа pthread_mutex_t будет правильно инициализирована без какого-либо явного присвоенного значения или вызова init из-за того, что статическая память заполнена нулями. Таким образом, вы явно динамически инициализировали один мьютекс, все остальные были неявно инициализированы для всех нулей.

4 голосов
/ 20 июля 2011

Вы всегда можете изменить это использование std::cout на printf(). Вы на Mac, POSIX-совместимой ОС. printf() гарантированно будет атомарным. На самом деле вам даже не нужен мьютекс, если вы можете использовать printf так, чтобы все выходные данные, которые должны быть созданы за один раз, выполнялись одним вызовом printf(). Нет никаких гарантий с std::cout. Ни один.

Если вы преобразуете это конкретное использование std::cout в printf, вы должны делать это во всем приложении. Смешивание std::cout и printf не лучшая идея.

0 голосов
/ 20 июля 2011

Это интересная проблема. Я не думаю, что это решает корневую проблему (синхронизация в ostream), но попробуйте это:

void InfoViewer::rule_x_fires() {
    // START CRITICAL REGION
    pthread_mutex_lock(&printer_mutex);
    cout << "INFO: Rule x fires" << endl;
    cout.flush();
    pthread_mutex_unlock(&printer_mutex);
    // END CRITICAL REGION
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...