Я написал программу Windows на С++, которая порой использует два потока: один фоновый поток для выполнения трудоемкой работы; и другой поток для управления графическим интерфейсом. Таким образом, программа по-прежнему реагирует на пользователя, что необходимо для того, чтобы прервать определенную операцию. Потоки обмениваются данными через общую переменную bool
, которая установлена в true
, когда поток GUI сигнализирует прерыванию рабочего потока. Вот код, который реализует это поведение (я удалил ненужные части):
КОД, ВЫПОЛНЕННЫЙ РЕЖИМАМИ GUI
class ProgressBarDialog : protected Dialog {
/**
* This points to the variable which the worker thread reads to check if it
* should abort or not.
*/
bool volatile* threadParameterAbort_;
...
BOOL CALLBACK ProgressBarDialog::DialogProc( HWND dialog, UINT message,
WPARAM wParam, LPARAM lParam ) {
switch( message ) {
case WM_COMMAND :
switch ( LOWORD( wParam ) ) {
...
case IDCANCEL :
case IDC_BUTTON_CANCEL :
switch ( progressMode_ ) {
if ( confirmAbort() ) {
// This causes the worker thread to be aborted
*threadParameterAbort_ = true;
}
break;
}
return TRUE;
}
}
return FALSE;
}
...
};
КОД, ВЫПОЛНЕННЫЙ РЕЗЬБОЙ РАБОТНИКА
class CsvFileHandler {
/**
* This points to the variable which is set by the GUI thread when this
* thread should abort its execution.
*/
bool volatile* threadParamAbort_;
...
ParseResult parseFile( ItemList* list ) {
ParseResult result;
...
while ( readLine( &line ) ) {
if ( ( threadParamAbort_ != NULL ) && *threadParamAbort_ ) {
break;
}
...
}
return result;
}
...
};
threadParameterAbort_
в обоих потоках указывает на переменную bool
, объявленную в структуре, которая передается рабочему потоку при создании. Он объявлен как
bool volatile abortExecution_;
Мой вопрос: Мне нужно использовать volatile
здесь, а код выше достаточно, чтобы гарантировать, что программа является потокобезопасной? То, как я обосновал использование volatile
здесь (см. этот вопрос для фона), заключается в том, что он будет:
-
предотвратить чтение
*threadParameterAbort_
для использования кеша и вместо этого получить значение из памяти и -
запретить компилятору удалять предложение
if
в рабочем потоке из-за оптимизации.
(В следующем абзаце речь идет только о безопасности потоков программы как таковой и не повторяет, повторяю, не требует утверждения, что volatile
каким-либо образом обеспечивает любые средства обеспечения безопасности потоков.) как я могу сказать, он должен быть потокобезопасным, так как установка переменной bool
должна в большинстве, если не во всех, архитектурах быть атомной операцией. Но я могу ошибаться. И меня также беспокоит, может ли компилятор переупорядочить инструкции, например, для нарушения безопасности потоков. Но лучше быть в безопасности (не каламбур), чем сожалеть.
РЕДАКТИРОВАТЬ:
Небольшая ошибка в моей формулировке вызвала вопрос, как будто я спрашивал, достаточно ли volatile
для обеспечения безопасности потоков. Это не мое намерение - volatile
действительно не обеспечивает безопасность потоков в любом случае, но я хотел спросить, был ли приведенный выше код демонстрирует правильное поведение, чтобы гарантировать, что программа является потокобезопасной.