多线程有时会给出不同的输出[重复]

Posted

技术标签:

【中文标题】多线程有时会给出不同的输出[重复]【英文标题】:multithreading gives different output sometimes [duplicate] 【发布时间】:2022-01-09 15:04:46 【问题描述】:

我目前正在尝试更好地了解多线程,并正在尝试使用 std::thread。

我有这段代码:

volatile int m = 0;
void ThdFun(int i)

    for (int j = 0; j < i; ++j) 
        m++;
        //std::cout << "hello1 " << m << " " <<std::endl;
    
    //std::cout << "Hello World from thread " << i <<"  " << std::endl;

int main()
    int var = 100000; //changes when i want to experiment with diff values

    std::thread t1(ThdFun, var);
    std::thread t2(ThdFun, var);
    t1.join();
    t2.join();
    std::cout << "final result of m: " << m << std::endl;

    if ((var * 2) == m) 
        std::cout << "CORRECT" << std::endl;
    
    else
        std::cout << "INCORRECT" << std::endl;
    return 0;

我注意到,如果我的 var = 2var =50,我得到正确的输出(分别是 4 和 100)

但是当我将var 设为像 100000 这样的大数字时,我会得到 100000-200000 范围内的任何值,而我预计会得到 200000。我想知道为什么会发生这种情况,因为据我了解不是'join()' 函数应该让它按顺序运行吗?另外,为什么“较小”数字的输出很好,但数字越大却变得不可预测?是 1 个线程完成并因此退出程序还是什么?

有人可以解释一下是什么导致了大数字的这种不同的输出,以及为什么 join() 不能很好地处理大数字吗?

谢谢!

【问题讨论】:

m 上的操作不是atomic @S.M.链接的问题适用于 C#。 你需要std::atomic而不是volatile 增加volatileatomic 的现场演示:godbolt.org/z/nbfsdY33j。 【参考方案1】:

您的问题是m++; 行。它真正的作用是这样的:

    m从内存读入寄存器 增加寄存器值 将寄存器值写回m

您的代码的问题是对m 的访问在线程之间不同步,因此一个线程可以读取m(第1 步),然后再写回递增的值(第 3 步),另一个线程已经读取了 m 的旧值。

在这种情况下,两个线程都读取并增加值,因为它是在另一个线程增加它之前,所以你失去了一个增量。

解决方案是添加同步。

幸运的是,这很简单,只需将m 的定义更改为std::atomic_int 即可。当变量声明为atomic时,语言保证m++操作不能被其他线程中断。

atomic 的替代方法是使用互斥体,但只有一次访问时,最好使用 atomic。

【讨论】:

正式来说,这里的问题是从多个线程执行m++ 会引入数据竞争:多个线程正在访问同一个对象,并且其中至少有一个正在写入。解决方案是添加同步。 (volatile 不这样做)。 +1。 @PeteBecker 你当然是对的。所以我根据你的评论扩展了答案。

以上是关于多线程有时会给出不同的输出[重复]的主要内容,如果未能解决你的问题,请参考以下文章

clock_gettime() 没有给出正确的输出[重复]

Openmp 多线程代码在使用多个线程时给出不同的答案

c ++多线程代码将优先级设置为不同的线程[重复]

jmeter 多线程组间变量共享

Jmeter (二十八)多线程组间变量共享

如何保证多线程从mysql数据库查询的数据不重复