我用C++编写了一个Windows程序,有时会使用两个线程:一个后台线程执行耗时的工作,另一个线程管理图形界面。这样程序对用户仍然响应,可以中止某个操作。线程之间通过共享的bool
变量通信,在GUI线程发出终止信号时设置为true
。下面是实现此行为的代码(已剥离无关部分):
由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
语句。
就我所知,它应该是线程安全的,因为在大多数体系结构中设置一个bool
变量应该是原子操作。但我可能是错的。我还担心编译器可能重新排序指令,从而破坏线程安全性。但最好还是保险起见。
编辑:我的措辞有点小问题,让问题似乎是在问volatile
是否足以确保线程安全。这不是我的意图--volatile
确实没有以任何方式确保线程安全--但我想问的是上述提供的代码是否表现出正确的行为以确保程序是线程安全的。
volatile
在编写多线程代码时很有用,正如在其中一个答案中链接的这篇文章(http://www.drdobbs.com/cpp/184403766)所示。 - gablinvolatile
可以帮助解决不足的线程库中的错误,但这已经不是问题了。(请记住,C++ 并没有正式设计用于多线程,因此如果像volatile
这样的语言特性有助于多线程,那只是巧合。)考虑到其他问题中讨论的问题,从头开始实现任何同步都是不够的。就像Jerry所说的,既不必要也不充分。永远不要使用它。熟悉您的线程库并使用干净、受支持的同步。 - Potatoswatter