首页 > 解决方案 > 关于多线程时的竞争条件的问题

问题描述

所以我正在阅读本章中关于多线程和并发的一本书,他们给了我一个对我来说没有意义的问题。

我想用参数 x 创建 3 个函数来简单地计算 x * x; 一种使用互斥锁,一种使用原子类型,一种都不使用。并创建 3 个保存值的全局变量。前两个函数将防止竞争条件,但第三个函数可能不会。

之后,我创建 N 个线程,然后循环并告诉每个线程计算它的 x 函数(3 个单独的循环,每个函数一个。所以我创建 N 个线程 3 次)

现在这本书告诉我,使用函数 1 和 2 我应该总是得到正确的答案,但使用函数 3 我不会总是得到正确的答案。但是,我总是得到所有这些的正确答案。我认为这是因为我只是在计算 x * x 这就是它所做的一切。

例如,当 N=3 时,正确的值为 0 * 0 + 1 * 1 + 2 * 2 = 5。

这是原子函数:

void squareAtomic(atomic<int> x)
{
    accumAtomic += x * x;
}

这就是我调用函数的方式

thread threadsAtomic[N]
for (int i = 0; i < N; i++) //i will be the current thread that represents x
    {
        threadsAtomic[i] = thread(squareAtomic, i);
    }

    for (int i = 0; i < N; i++)
    {
        threadsAtomic[i].join();
    }

这是有时应该创建竞争条件的函数:

void squareNormal(int x) 
{
    accumNormal += x * x;
}

我是这样称呼的:

thread threadsNormal[N];
    for (int i = 0; i < N; i++) //i will be the current thread that represents x
    {
        threadsNormal[i] = thread(squareNormal, i);
    }

    for (int i = 0; i < N; i++)
    {
        threadsNormal[i].join();
    }

这都是我自己的代码,所以我可能没有正确地回答这个问题,在这种情况下我道歉。

标签: c++multithreadingconcurrencymutexrace-condition

解决方案


One problem with race conditions (and with undefined behavior in general) is that their presence doesn't guarantee that your program will behave incorrectly. Rather, undefined behavior only voids the guarantee that your program will behave according to rules of the C++ language spec. That can make undefined behavior very difficult to detect via empirical testing. (Every multithreading-programmer's worst nightmare is the bug that was never seen once during the program's intensive three-month testing period, and only appears in the form of a mysterious crash during the big on-stage demo in front of a live audience)

在这种情况下,您的 racy 程序的竞态条件以多个线程同时读写的形式出现accumNormal;特别是,如果线程 A 读取 的值accumNormal,然后线程 B 将新值写入accumNormal,然后线程 A 将新值写入 ,则可能会得到不正确的结果,从而accumNormal覆盖线程 B 的值。

If you want to be able to demonstrate to yourself that race conditions really can cause incorrect results, you'd want to write a program where multiple threads hammer on the same shared variable for a long time. For example, you might have half the threads increment the variable 1 million times, while the other half decrement the variable 1 million times, and then check afterwards (i.e. after joining all the threads) to see if the final value is zero (which is what you would expect it to be), and if not, run the test again, and let that test run all night if necessary. (and even that might not be enough to detect incorrect behavior, e.g. if you are running on hardware where increments and decrements are implemented in such a way that they "just happen to work" for this use case)


推荐阅读