当编写需要在应用程序和中断例程/线程/回调例程之间共享文件范围变量的 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
变得多余。在对信号量进行任何操作后,编译器将始终重新加载 int flag
。
Fred Larson 已经预见到了这一点。 volatile
在没有锁的情况下是不够的,在有锁的情况下是冗余的。这使得它对于线程安全编程毫无用处。
关于c++ - 用 C++ 实现的可移植线程类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5107171/