这段代码线程安全吗?如果不是何时以及如何出错?

Pet*_*ham 3 c++ multithreading

好的,所以我被告知这段代码不是线程安全的.

#include <iostream>
#include <thread>

static int sum[5];

static int get_sum()
{
    int x=0;
    for (int j=0;j<5;++j)
        x += sum[j];
    return x;
}

static void f1(int x){
    sum[x] = 1;
    std::cout << "f" <<x << ": " << sum[x] << " : " << get_sum() << std::endl;
}

int main()  {

    for (int j=0;j<5;++j)
        sum[j] = 0;

    std::thread t0(f1, 0);
    std::thread t1(f1, 1);
    std::thread t2(f1, 2);
    std::thread t3(f1, 3);
    std::thread t4(f1, 4);

    while (get_sum() != 5)  ;

    t0.join();
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    std::cout << "final: " << get_sum() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释为什么该程序可能无法完成?我知道get_sum的运行值将是非确定性的,cout的输出将被随机交错,但这与程序完成无关.

Dav*_*rtz 12

可能无法在一个线程中访问值,而在另一个线程中可能会在另一个线程中修 这是规则.

我们可以推测特定平台上可能出现的特定问题.但一般来说,这是无益的,因为它会让人们认为,如果他们能够尽可能地修复每一种可能的方式,他们就会想到它可能会出错,那么他们的代码就可以了.但事实并非如此 - 事情可以而且确实会以你当时无法想到的方式出错.请不要这样想.由此类推理引起的失败列表很长,不需要再进行.

这是它失败的一种方式:编译器可能会get_sum在while循环之前将所有值内联并复制到寄存器中,从而导致循环永远重复.这是一个合法的优化,因为编译器可以看到您的代码可以在while循环期间的任何时间读取任何这些值,因此在该循环期间不允许其他线程修改它们.

现在,如果你阅读这个问题和答案,你会发现很多人都不会想到代码可能出错的方式.但是没关系,他们没有必要.存在这些规则是因为考虑代码可能出错的所有可能方式很困难,甚至不可能.因此,不要让你的代码的正确性依赖于你拥有超人类的能力.

  • 你有点不为人知.即使没有人能想到任何可能失败的方式,该规则也适用.(但无论如何,我会用一个更新我的答案.) (2认同)