gab*_*lin 11 c++ multithreading volatile
我用C++编写了一个Windows程序,它有时使用两个线程:一个后台线程用于执行耗时的工作; 和另一个用于管理图形界面的线程.这样,程序仍然响应用户,这需要能够中止某个操作.线程通过共享bool
变量进行通信,该变量设置为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;
}
...
};
Run Code Online (Sandbox Code Playgroud)
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;
}
...
};
Run Code Online (Sandbox Code Playgroud)
threadParameterAbort_
在两个线程中都指向bool
在结构中声明的变量,该变量在创建时传递给工作线程.它被宣布为
bool volatile abortExecution_;
Run Code Online (Sandbox Code Playgroud)
我的问题是:我需要在volatile
这里使用,上面的代码是否足以确保程序是线程安全的?我推断在volatile
这里使用这个问题的理由(参见这个问题的背景)是它将:
阻止读取*threadParameterAbort_
使用缓存,而是从内存中获取值,并且
防止编译器if
因优化而删除工作线程中的子句.
(下面的段落只关心程序的多线程安全等,并没有,我再说一遍,不涉及声称volatile
以任何方式提供保证线程安全的任何手段).据我所知,它应该是线程安全的,因为bool
在大多数(如果不是全部)架构中,设置变量应该是原子操作.但我可能是错的.而且我也担心编译器是否可能重新排序指令,例如破坏线程安全性.但更好的是安全(没有双关语意)而不是抱歉.
编辑:
我的措辞中的一个小错误使问题看起来好像我在问是否volatile
足以确保线程安全.这不是我的意图 - volatile
确实不能确保任何方式的线程安全 - 但我要问的是,上面提供的代码是否表现出正确的行为以确保程序是线程安全的.
dor*_*ron 14
您不应该依赖volatile来保证线程安全,这是因为即使编译器将保证始终从内存中读取变量(而不是寄存器缓存),在多处理器环境中也需要内存屏障.
而是在共享内存周围使用正确的锁.像关键部分这样的锁通常非常轻量级,并且在没有争用的情况下可能都是用户实现的.它们还将包含必要的记忆障碍.
Volatile仅应用于内存映射IO,其中多个读取可能返回不同的值.类似地,对于内存映射写入
维基百科说得很好.
在C和C++中,volatile关键字旨在允许访问内存映射设备,允许在setjmp之间使用变量,允许在信号处理程序中使用sig_atomic_t变量
对volatile变量的操作不是原子的,也不是为线程建立正确的先发生关系.这是根据相关标准(C,C++,POSIX,WIN32),这对于绝大多数当前实现来说都是事实.volatile属性作为便携式线程构造基本上没有价值.