簡體   English   中英

cpp線程加入如果兩個線程相互依賴應該使用join導致死鎖

[英]cpp thread join if two threads rely each other should using join cause deadlock

#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 標識的線程完成其執行。”

我的理解是主要的 thead 應該停止。 它一直等到線程 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();
}

同樣的問題

您做出了錯誤的假設,即互斥鎖可以從不同的線程鎖定和解鎖。

一個線程鎖定的互斥鎖不能被另一個線程解鎖。 整個鎖定/解鎖過程是每個線程。

 lock_bar_.unlock();

第一個函數中的這一行沒有意義。 請參閱 Windows 中的ReleaseMutex (我猜它在其他操作系統中也是如此)。 它從當前線程釋放先前鎖定的互斥鎖,而不是從任何其他線程釋放。

你的線程做的工作很少。 根據您的操作系統和 cpu 內核的數量,線程只會以固定的時間間隔切換。 t1.join返回t2之后, t1.join可能已經完成執行(您的第一個輸出)。

如果您向線程中的循環添加一些睡眠,則每次都應該看到第二個輸出,因為t1.join返回時t2仍將執行。

請注意,從最初沒有鎖定互斥鎖的線程解鎖互斥鎖具有未定義的行為: https : //en.cppreference.com/w/cpp/thread/mutex/unlock

答案是當 std::thread t2{} 創建時,它進入隊列。 這就是為什么 t2 也被執行的原因。 join() 確實意味着 start()。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM