代码之家  ›  专栏  ›  技术社区  ›  YotKay

为什么使用互斥锁[关闭]从线程进行奇怪的打印

  •  2
  • YotKay  · 技术社区  · 7 年前

    我认为这段代码,我使用互斥锁在线程之间进行同步,将优雅地打印从0到10的数字,连续打印3次。

    #include <iostream>
    #include <mutex>
    #include <thread>
    
    using namespace std;
    
    struct A
    {   
        void run() 
        {       
            lock_guard<mutex> l(mutex);
            int i = 0;
            while (i <= 10)
                cout << "i = " << i++ << endl;            
        }
    
        std::mutex mut;
    };
    
    int main()
    {
        A a;
        thread t1(&A::run, &a);
        thread t2(&A::run, &a);
        thread t3(&A::run, &a);
    
        t1.join();
        t2.join();
        t3.join();
    }
    

    但由于某些原因,输出的开头总是或多或少地被损坏。其余的有时是好的,有时不是。因此,很明显,它是不同步的。这很奇怪,因为我预计当一个线程锁定互斥体时,没有其他线程会进入run方法的主体。但显然这不是真的。

    i = i = 00i = 0
    
    i = 1
    i = 2
    i = 3
    

    有人能解释一下吗?

    我认为可能需要用std::ref围绕线程构造函数中的“a”对象,但这没有帮助。

    3 回复  |  直到 7 年前
        1
  •  7
  •   Ron Alan    7 年前

    这:

    lock_guard<mutex> l(mutex);
    

    声明函数 l 类型 lock_guard<mutex> 接受 std::mutex std::lock_guard 包装器。您想声明类型为的变量 std::lock_guard 并用一个 mut

    std::lock_guard<std::mutex> l(mut);
    

    为了避免这种混淆,不要使用 using namespace std; .

        2
  •  1
  •   YotKay    7 年前

    答案是我打错了。我没有写“mut”,而是输入了“mutex”。代码的编译令人惊讶,但正如注释中所述,我这样声明了一个函数,而不是锁定了一个互斥体(“最麻烦的解析”)。这就是为什么“run”方法的代码在线程之间不同步的原因。

        3
  •  0
  •   Kieveli    7 年前

    这是一个输入错误:“应该是lock\u guard l(mut);”但还是要试试这个:

    #include <iostream>
    #include <mutex>
    #include <thread>
    
    using namespace std;
    
    struct A
    {   
        void run() 
        {       
            int i = 0;
            while (i <= 10)
                printOutput(i);
        }
    
        void printOutput(int i)
        {
            lock_guard<mutex> l(mut);
            cout << "i = " << i++ << endl;            
        }
    
        std::mutex mut;
    };
    
    int main()
    {
        A a;
        thread t1(&A::run, &a);
        thread t2(&A::run, &a);
        thread t3(&A::run, &a);
    
        t1.join();
        t2.join();
        t3.join();
    }
    

    我想你会发现输出更有趣。。。有时在调试编译和优化的情况下尝试-它们的行为可能不同。