需要帮助识别简单多线程代码中的错误

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&lt;int&gt;,或者使用互斥锁(适当的互斥锁——天真的 while 循环不计算在内)保护对它的所有访问,或者确保两个线程都不会改变它的值。 @JeremyFriesner,这里给出的问题陈述 - leetcode.com/problems/print-foobar-alternately 希望它的求解器允许两个不同的线程访问类 FooBar 的共享对象。我正在使用状态变量来确保输出始终为 FooBarFooBarFooBar.... 的形式。请通过上面给出的链接。 同样,一个普通的int 不能以您尝试使用它的方式可靠地使用。在线程之间共享读/写变量需要特殊处理,除非您向编译器表明您需要特殊处理(例如,通过将变量声明为 std::atomic&lt;int&gt; 而不仅仅是 int),否则编译器将不会生成执行您希望它执行的操作所需的代码,并且您的程序将无法正常工作(例如,当线程 A 将 state 的值设置为 1 时,线程 B 可能永远不会“看到”其值更改,而是可能循环while(state==0);永远) @JeremyFriesner,我尝试将 state 的数据类型从 int 更改为 std:atomic,同时保持其余代码相同,在线法官仍在说 - “超出时间限制”。还有什么想法吗? 简单的多线程代码是矛盾的。 【参考方案1】:

虽然循环不是锁。锁只允许一个线程通过。在您的代码中,如果 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。

【讨论】:

以上是关于需要帮助识别简单多线程代码中的错误的主要内容,如果未能解决你的问题,请参考以下文章

需要有关 gtkmm 中的多线程的帮助

libcurl 中的分段错误,多线程

java多线程编程

Java多线程编程

Python中的多处理:处理多个工作线程

java - 多线程中的简单计算比单线程中需要更长的时间