編程代碼
新聞詳情

C++ 線程間同步

發布時(shí)間:2021-03-29 09:36:33 最後更新:2021-03-30 09:02:29 浏覽次數:3670

0 前言

  • 多線程在(zài)運行過程中,各個(gè)線程都是(shì)随着 OS 的(de)調度算法,占用 CPU 時(shí)間片來(lái)執行指令做事情,每個(gè)線程的(de)運行完全沒有順序可言。
  • 在(zài)某些應用場景下,一(yī / yì /yí)個(gè)線程需要(yào / yāo)等待另外一(yī / yì /yí)個(gè)線程的(de)運行結果,才能繼續往下執行,這(zhè)就(jiù)涉及到(dào)線程之(zhī)間的(de)同步通信機制。
  • 線程間同步通信最典型的(de)例子(zǐ)就(jiù)是(shì)生産者-消費者模型,生産者線程生産出(chū)産品以(yǐ)後,會通知消費者線程去消費産品;當消費者線程去消費産品時(shí),發現還沒有産品生産出(chū)來(lái),它需要(yào / yāo)通知生産者線程趕快生産産品,等生産者線程生産出(chū)産品以(yǐ)後,消費者線程才能繼續往下執行。

1 消費者“被動等待”

#include 
#include 
#include 

static std::mutex mtx;
static std::deque<int> dq;
static int productNum = 5;

void Producer()
{
    using namespace std::literals::chrono_literals;
    for (int i = 1; i <= productNum; ++i) {
        mtx.lock();
        dq.push_front(i);
        std::cout << "Producer 生産産品爲(wéi / wèi): " << i << std::endl;
        mtx.unlock();
        // std::this_thread::sleep_for(1s);
    }
}

void Consumer()
{
    while (true) {
        if (dq.empty()) {
            continue;
        }
        mtx.lock();
        int data = dq.back();
        dq.pop_back();
        std::cout << "Consumer 消費産品爲(wéi / wèi): " << data << std::endl;
        mtx.unlock();
    }
}

int main()
{
    std::thread t1(Producer);
    std::thread t2(Consumer);
    t2.join();
    t1.join();
    std::cin.get();
}

程序運行結果如下:

C++ 線程間同步

如果讓生産者線程每生産一(yī / yì /yí)個(gè)産品後休息(sleep) 1s,結果如下:

C++ 線程間同步

解釋:該例子(zǐ)中,生産者和(hé / huò)消費者分别對應兩個(gè)線程。隊列中存在(zài)物品時(shí),消費者去消費,否則空循環,一(yī / yì /yí)直等待。

缺點:當雙端隊列中沒有物品時(shí),消費者隻會原地(dì / de)死等,不(bù)會去催。

2 消費者“主動出(chū)擊”

#include 
#include 
#include 
#include 
#include 
  
std::mutex mtx;
std::condition_variable cv;
std::vector<int> vec;
int productNum = 5;

void Producer()
{
    for (int i = 1; i <= productNum; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        while (!vec.empty()) {
            cv.wait(lock); // vec 不(bù)爲(wéi / wèi)空時(shí)阻塞當前線程
        }
        vec.push_back(i);
        std::cout << "Producer生産産品: " << i << std::endl;
        cv.notify_all(); // 釋放線程鎖
    }
}

void Consumer()
{
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        while (vec.empty()) {
            cv.wait(lock); // vec 爲(wéi / wèi)空時(shí)等待線程鎖。其他(tā)線程鎖釋放時(shí),當前線程繼續執行
        }
        int data = vec.back();
        vec.pop_back();
        std::cout << "Consumer消費産品: " << data << std::endl;
        cv.notify_all();
    }
}

int main()
{
    std::thread t1(Producer);
    std::thread t2(Consumer);
    t2.join();
    t1.join();
    std::cin.get();
}

程序運行結果如下:

C++ 線程間同步

解釋:該例子(zǐ)中,生産者和(hé / huò)消費者分别對應兩個(gè)線程。隻要(yào / yāo) vector 中存在(zài)物品時(shí),生産者線程就(jiù)阻塞,通知消費者線程去消費;vector 中不(bù)存在(zài)物品時(shí),消費者線程阻塞,通知生産者去生産。

3 線程加入方式 join 和(hé / huò) detach

join:采用 join 方式,t1、t2 亂序執行,且外層主線程會等到(dào) t1、t2 都結束了(le/liǎo)再繼續執行後面的(de)代碼。

detach:如果采用 detach 方式,t1、t2 亂序執行,且脫離了(le/liǎo)外層主線程。外層主線程執行結束時(shí),t1、t2 可能還沒結束,但此時(shí)程序就(jiù)退出(chū)了(le/liǎo)。


如涉及侵權,請相關權利人(rén)與我司聯系删除

在(zài)線客服 雙翌客服
客服電話
  • 0755-23712116
  • 13310869691