volatile用于信号处理程序和多线程

时间:2017-02-11 23:25:27

标签: c++ c multithreading volatile

据说信号处理程序需要volatile,例如,

volatile int flag = 1; // volatile is needed here?

void run() {
    while(flag) { /* do someting... */ }
}

void signal_handler(int sig) {
    flag = 0;
}

int main() {
    signal(SIGINT, sig_handler);
    run();
    // ...
}

据说volatile通常不用于多线程。但是多线程中类似的情况如何:

int flag = 1; // is volatile needed here?

void thread_function() {
    while(flag) { /* do someting... */ }
}

int main() {
    // pthread_create() to create thread_function()...
    sleep(10); // let thread_function run for 10 seconds
    flag = 0;
    // ...
}

在两种情况下都应该使用volatile关键字吗?这两种情况是否由编译器以相同的方式处理?

3 个答案:

答案 0 :(得分:6)

允许从信号处理程序修改的唯一非本地值是volatile sig_atomic_t类型和原子类型。特别是,写入volatile int 是允许的,如果您的信号处理程序运行,则您有未定义的行为。

答案 1 :(得分:1)

volatile用于确保从实际内存中读取变量的内容,而不是从CPU寄存器中读取。

换句话说,每当“外部”事件可能改变变量的值时,您应该考虑使用volatile(“外部” - 在相关代码块之外)。

在两个示例中,您都使用变量作为标志来表示行为的变化。在两个示例中,该标志由正在查看标志的循环“外部”的事件控制。因此,这两个示例都需要使用volatile关键字。

应该注意volatile 出于多种原因提供线程安全性。为了确保对象是线程安全的,读/写操作必须是受保护的或原子的。

答案 2 :(得分:1)

[intro.execution]第6段中的c ++标准说明:

  

当抽象机的处理由于接收到信号而中断时,这两个对象的值都不是
           —类型为volatile std :: sig_atomic_t或
           —无锁原子对象(29.4)
  在执行信号处理程序期间未指定,并且未被处理程序修改的这两个类别中任何一个类别的任何对象的值都将变为未定义。

因此,是的,对于信号处理程序,您必须使用volatile std::sig_atomic_t