多线程有时会给出不同的输出[重复]
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 = 2
或 var =50
,我得到正确的输出(分别是 4 和 100)
但是当我将var
设为像 100000 这样的大数字时,我会得到 100000-200000 范围内的任何值,而我预计会得到 200000。我想知道为什么会发生这种情况,因为据我了解不是'join()' 函数应该让它按顺序运行吗?另外,为什么“较小”数字的输出很好,但数字越大却变得不可预测?是 1 个线程完成并因此退出程序还是什么?
有人可以解释一下是什么导致了大数字的这种不同的输出,以及为什么 join() 不能很好地处理大数字吗?
谢谢!
【问题讨论】:
m
上的操作不是atomic
@S.M.链接的问题适用于 C#。
你需要std::atomic
而不是volatile
增加volatile
与atomic
的现场演示: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 你当然是对的。所以我根据你的评论扩展了答案。以上是关于多线程有时会给出不同的输出[重复]的主要内容,如果未能解决你的问题,请参考以下文章