首页 > 解决方案 > cpp线程连接如果两个线程相互依赖应该使用连接导致死锁

问题描述

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
std::mutex lock_bar_;

std::mutex lock_foo_;
int n = 3;

void foo() {

    for (int i = 0; i < n; i++) {
        lock_foo_.lock();
        // printFoo() outputs "foo". Do not change or remove this line.
        std::cout << "1\n";
        lock_bar_.unlock();
    }
}

void bar() {

    for (int i = 0; i < n; i++) {
        lock_bar_.lock();
        // printBar() outputs "bar". Do not change or remove this line.
        std::cout << "2\n";
        lock_foo_.unlock();
    }
}

int main(){
    lock_bar_.lock();
    std::thread t1{foo};
    std::thread t2{bar};

    t1.join();            // line 1
    std::cout << "333\n"; // line 2
    t2.join();            // line 3
    std::cout << "3\n";   // line 4
}

结果是

1
2
1
2
1
2
333
3

或者

1
2
1
2
1
333
2
3

我的问题是:为什么这个程序可以不死锁地运行?

join() 实际上是如何工作的?

当程序执行第 1 行时,根据 cppreference https://en.cppreference.com/w/cpp/thread/thread/join

“阻塞当前线程,直到 *this 标识的线程完成执行。”

我的理解是主要的主题应该停止。它一直等到线程 t1 完成。然后执行第 2 行和其余的。但程序似乎执行第 1 行和第 3 行。当线程 t1 完成时,它运行第 2 行。当线程 t2 完成时,它执行第 4 行。我对 join() 感到困惑。

如果有人可以提供帮助,非常感谢

第一次编辑:

忽略原程序

新程序是

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>

int n = 10;
bool first = true;
std::condition_variable cv1;
std::condition_variable cv2;
std::mutex m;



void foo() {
    std::unique_lock<std::mutex> ul(m, std::defer_lock);
    for (int i = 0; i < n; i++) {
        ul.lock();
        cv1.wait(ul, [&]()->bool {return first;} );
        std::cout << "1\n";
        // printFoo() outputs "foo". Do not change or remove this line.
        first = !first;
        ul.unlock();
        cv2.notify_all();
    }
}

void bar() {
    std::unique_lock<std::mutex> ul(m, std::defer_lock);
    for (int i = 0; i < n; i++) {
        ul.lock();
        cv2.wait(ul, [&]()->bool {return !first;} );
        // printBar() outputs "bar". Do not change or remove this line.
        std::cout << "2\n";
        first = !first;
        ul.unlock();
        cv1.notify_all();
    }
}

int main(){
    std::thread t1{foo};
    std::thread t2{bar};

    t1.join();
    std::cout << "3\n";
    t2.join();
}

同样的问题

标签: c++multithreading

解决方案


你的线程做的工作很少。根据您的操作系统和 cpu 内核的数量,线程只会以固定的时间间隔切换。很有可能在t1.join返回后t2已经完成执行(您的第一个输出)。

如果您在线程中的循环中添加一些睡眠,您应该每次都会看到您的第二个输出,因为在返回t2时仍将执行。t1.join

请注意,从最初未锁定互斥锁的线程解锁互斥锁具有未定义的行为:https ://en.cppreference.com/w/cpp/thread/mutex/unlock


推荐阅读