【问题标题】:c++11 threads, why this program keep running infinitly in release modec++11线程,为什么这个程序在发布模式下无限运行
【发布时间】:2013-08-22 16:49:10
【问题描述】:
#include <iostream>
#include <thread>


int x = 0;
int y = 0;

void f()
{
    std::cout <<"f called\n";

    static int c = 0;
    while(y == 0)
    {
        ++c;
    }
    std::cout << "c=" << c << std::endl;
    std::cout << "x=" << x << std::endl;
}

void g()
{
    std::cout <<"g called\n";
    x = 42;
    y = 1;
}

int main()
{
    std::thread t1(f);
    std::thread t2(g);

    t1.join();
    t2.join();

    return 0;
}

当从另一个线程设置标志 y 时,f 应该打印“x=42”(嗯,它也可以打印 x=0,但这不是这里的问题)

在调试模式下运行时,它按预期工作:

f called
g called
c=80213
x=42

但在发布模式下,第二个线程似乎冻结并且程序永远不会结束:

f called
g called

有人能解释一下原因吗?

PS。 该程序是用mignw g++ 4.8.0编译的

【问题讨论】:

  • 数据竞争、未定义的行为等。A.k.a. “多线程真的很难,即使你的 hello world 也会出错。”
  • @Kerrek SB,是的,这绝对是数据竞争条件,但我的问题是,为什么即使 'y' 中的值从 0 变为第一个线程仍然运行?
  • 这是“未定义的行为”:任何事情都可能发生。事实上,任何事情都发生了。所以一切都如预期的那样。
  • 最有可能的是,编译器看到 while 循环不可能终止,因为 y 不是原子的并且循环中没有同步,因此对 y 的任何修改都将是未定义的,所以它用无限循环替换整个循环。
  • @Sebastian Redl,对此不确定,因为当我在循环中添加 std::cout 时问题消失了.. while(y

标签: multithreading c++11


【解决方案1】:

C++11 线程内存模型不要求一个线程中的代码会看到由另一个线程中的代码引起的内存变化除非

  1. 两个线程通过使用std::mutex 同步它们对内存的访问。也就是说,接收线程必须等待写入线程持有的互斥体。并且写入线程必须在释放该互斥体之前写入数据。
  2. 有问题的内存由std::atomic 管理,并使用适当的原子内存访问对其进行写入和读取。

如果这些事情都不在起作用,那么一个线程从内存中读取可能被另一个线程修改的任何尝试都被认为是“数据竞争”。因此会导致未定义的行为。

【讨论】:

  • 在这种情况下,y volatile 可以帮助/解决问题吗?
  • @RedX: No.
  • @RedX,是的。我可以确认让 y volatile 解决了这个问题。
  • @user327843:未定义的行为意味着未定义的行为。仅仅因为您的代码有效并不意味着 C++ 标准保证它会。就 C++ 标准而言,volatile 有千斤顶与跨线程内存更改的可见性有关。
  • @NicolBolas 谢谢你的链接。
猜你喜欢
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多