需要帮助识别简单多线程代码中的错误
Posted
技术标签:
【中文标题】需要帮助识别简单多线程代码中的错误【英文标题】:Need Help Identifying Bug in Simple Multithreaded Code 【发布时间】:2019-07-12 23:22:29 【问题描述】:我试图解决这里给出的问题 - https://leetcode.com/problems/print-foobar-alternately/。
我编写了以下代码来解决问题,但它超出了分配的时间限制。我无法理解为什么会这样。有人可以指出我的错误吗?另外,我怎样才能更正下面给出的代码,以便它在仅使用 while 循环充当互斥锁时执行得更快?
class FooBar
private:
int n;
int state = 0;
public:
FooBar(int n)
this->n = n;
state = 0;
void foo(function<void()> printFoo)
for (int i = 0; i < n; i++)
// printFoo() outputs "foo". Do not change or remove this line.
while(state == 1);
printFoo();
state = 1;
void bar(function<void()> printBar)
for (int i = 0; i < n; i++)
// printBar() outputs "bar". Do not change or remove this line.
while(state == 0);
printBar();
state = 0;
;
【问题讨论】:
您正在从两个线程访问值state
;这会创建一个竞争条件并调用未定义的行为,除非您将state
更改为std::atomic<int>
,或者使用互斥锁(适当的互斥锁——天真的 while 循环不计算在内)保护对它的所有访问,或者确保两个线程都不会改变它的值。
@JeremyFriesner,这里给出的问题陈述 - leetcode.com/problems/print-foobar-alternately 希望它的求解器允许两个不同的线程访问类 FooBar 的共享对象。我正在使用状态变量来确保输出始终为 FooBarFooBarFooBar.... 的形式。请通过上面给出的链接。
同样,一个普通的int
不能以您尝试使用它的方式可靠地使用。在线程之间共享读/写变量需要特殊处理,除非您向编译器表明您需要特殊处理(例如,通过将变量声明为 std::atomic<int>
而不仅仅是 int
),否则编译器将不会生成执行您希望它执行的操作所需的代码,并且您的程序将无法正常工作(例如,当线程 A 将 state
的值设置为 1 时,线程 B 可能永远不会“看到”其值更改,而是可能循环while(state==0);
永远)
@JeremyFriesner,我尝试将 state 的数据类型从 int 更改为 std:atomic虽然循环不是锁。锁只允许一个线程通过。在您的代码中,如果 state=0 两个线程可能一个接一个地打印 foo 。要解决此问题,请使用互斥锁和唯一锁。
for (int i = 0; i < n; i++)
// printFoo() outputs "foo". Do not change or remove this line.
while(state==1);
unique_lock<mutex> lck(m1); //Make mutex m1 as a global mutex
printFoo();
state = 1;
永远不要跨线程读取相同的变量,除非它是原子的或修改锁中的变量。在此示例中,由于值状态在共享互斥体中发生变化,因此您无需使用 atomic。
【讨论】:
以上是关于需要帮助识别简单多线程代码中的错误的主要内容,如果未能解决你的问题,请参考以下文章