【发布时间】:2011-02-24 16:05:02
【问题描述】:
在编写需要在应用程序和中断例程/线程/回调例程之间共享文件范围变量的 C 程序时,众所周知,必须将变量声明为 volatile,否则编译器可能会做错优化。这是我的意思的一个例子:
int flag;
void some_interrupt (void)
{
flag = 1;
}
int main()
{
flag = 0;
...
/* <-- interrupt occurs here */
x = flag; /* BUG: the compiler doesn't realize that "flag" was changed
and sets x to 0 even though flag==1 */
}
为了防止上述错误,“flag”应该被声明为 volatile。
我的问题是:在创建包含线程的类时,这如何应用于 C++?
我的课程看起来像这样:
class My_thread
{
private:
int flag;
static void thread_func (void* some_arg) // thread callback function
{
My_thread* this_ptr= (My_thread*)some_arg;
}
};
“some_arg”将包含一个指向该类实例的指针,因此“My_thread”的每个对象都有自己的线程。通过这个指针,它将访问成员变量。
这是否意味着“this_ptr”必须声明为指向易失性数据的指针? “标志”也必须是易变的吗?如果是这样,我是否必须使所有修改“标志”的成员函数变为 volatile?
我对特定操作系统或编译器的行为方式不感兴趣,我正在寻找一种通用的、完全可移植的解决方案。
编辑:这个问题与线程安全无关!
真正的代码会有信号量等。
为了澄清,我希望避免由于编译器不知道回调函数可能从程序本身之外的源调用而导致的错误,从而对是否使用某些变量做出错误的结论。我知道如何在 C 中执行此操作,如第一个示例所示,但在 C++ 中不知道。
【问题讨论】:
-
也许是众所周知的,但是错了。
volatile不会使操作成为原子操作,并且可能不会对多线程提供帮助。 -
太真实了,volatile 在这里无济于事。如果是这样,它将是特定于编译器的。您是否考虑过使用 Boost 实现? boost.org/doc/libs/1_42_0/doc/html/thread.html
-
volatile会在某种程度上解决问题,但它仍然是错误的解决方案。你需要一个内存屏障,而不是volatile。 (并且您可能还需要使用 CPU 的原子指令来设置/测试标志,具体取决于平台) -
您说您可能需要将
this_ptr声明为“指向易失性数据的指针”是什么意思?您想要指向My_thread对象的指针,因此将其声明为My_thread*。使类成员volatile不会使它们成为线程安全的。您需要使用事件和/或互斥锁来实现这一点。这个问题很有趣:stackoverflow.com/questions/2484980/… -
由于当前的 C 和 C++ 标准都没有标准线程库,因此您无法编写通用且完全可移植的线程代码。在 C++0x 被广泛使用之前,您将获得的最接近的是 Boost::Thread。
标签: c++ multithreading volatile