自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

多線程背景下,讀請求不斷,寫請求有機(jī)會執(zhí)行嗎?怎么分析?

開發(fā) 前端
在多線程編程中,讀寫鎖(Read-Write Lock)的機(jī)制是否會導(dǎo)致寫請求在持續(xù)讀請求下無法執(zhí)行(即 寫線程饑餓),取決于鎖的具體實現(xiàn)策略和場景特性。

先用代碼測試下題目當(dāng)中的情況(完整代碼,可以直接復(fù)制用來測試,文末抽獎送書,歡迎參與) 

#include <shared_mutex>
#include <thread>
#include <vector>
#include <iostream>
#include <chrono>

std::shared_mutex rw_mutex;
std::string shared_data;

void reader(int id){
    while (true)
    {
        std::shared_lock lock(rw_mutex);
        std::cout << "Reader " << id << " reads: " << shared_data << std::endl;

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void writer(const std::string& new_data){
    
    while (true)
    {
        std::unique_lock lock(rw_mutex);
        shared_data = new_data;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){
    std::vector<std::thread> readers;
    for (int i = 0; i < 5; ++i) {
        readers.emplace_back(reader, i);
    }
    std::thread writer_thread(writer, "Updated Data");
    for (auto& t : readers) {
        t.join();
    }
    writer_thread.join();

    getchar();
    return0;
}

VS2022 執(zhí)行代碼后,觀察控制臺輸出:

ImageImage

讀線程持續(xù)打印 “Reader X reads: Updated Data”(初始值為空)?!?/p>

寫線程在測試期間未能成功獲取鎖,導(dǎo)致 shared_data 未被更新為 “Updated Data” 

我這里代碼故意在讀處理中加了延時,讀線程長時間持有鎖,然后是 5 個讀線程,可以發(fā)現(xiàn)寫請求完全得不到機(jī)會來處理?!?/p>

這個現(xiàn)象有個專業(yè)名詞叫:寫線程饑餓?!?/p>

在多線程編程中,讀寫鎖(Read-Write Lock)的機(jī)制是否會導(dǎo)致寫請求在持續(xù)讀請求下無法執(zhí)行(即 寫線程饑餓),取決于鎖的具體實現(xiàn)策略和場景特性。以下是逐步分析: 

一、讀寫鎖的基本行為

讀寫鎖的核心規(guī)則是 “讀共享,寫?yīng)氄肌保骸?/p>

  • 讀鎖(共享鎖):允許多個線程同時讀取資源。
  • 寫鎖(獨占鎖):同一時間僅允許一個線程寫入資源,且寫入時會阻塞所有讀鎖和寫鎖。

因此,當(dāng)讀鎖持續(xù)占用時,寫鎖必須等待所有讀鎖釋放后才能獲取。但具體能否執(zhí)行需結(jié)合鎖的調(diào)度策略分析?!?/p>

鎖獲取優(yōu)先級:  

無公平性策略:若讀鎖持續(xù)被獲取,寫鎖可能無限等待(饑餓)。  

寫優(yōu)先策略:當(dāng)寫鎖請求存在時,后續(xù)讀鎖會被阻塞,直到寫鎖完成。  

公平策略:交替服務(wù)讀/寫請求,避免單一方饑餓。 

二、寫請求能否執(zhí)行的場景分析

場景 1:讀寫鎖無公平性策略(常見默認(rèn)實現(xiàn))

問題:若讀線程持續(xù)獲取讀鎖(無間隙釋放鎖),寫線程可能永遠(yuǎn)無法執(zhí)行。  

示例代碼:  

std::shared_mutex rw_mutex;
void reader() {
    while (true) {
        std::shared_lock lock(rw_mutex); // 持續(xù)持有讀鎖
        // 讀操作...
    }
}
void writer() {
    std::unique_lock lock(rw_mutex); // 永遠(yuǎn)無法獲取寫鎖
    // 寫操作...
}

結(jié)果:寫線程饑餓。 

場景 2:讀寫鎖支持寫優(yōu)先

策略:當(dāng)有寫鎖等待時,新讀鎖請求被阻塞,直到寫鎖完成。  

實現(xiàn)方式:維護(hù)寫等待標(biāo)記(如計數(shù)器),讀鎖獲取前檢查該標(biāo)記。  

結(jié)果:寫線程最終能獲得鎖,但可能犧牲讀吞吐量?!?/p>

場景 3:讀寫鎖支持公平性

策略:通過隊列或時間戳保證讀/寫請求按到達(dá)順序交替執(zhí)行。  

示例:Linux 內(nèi)核的 rw_semaphore 使用公平隊列。  

結(jié)果:寫線程不會饑餓,但并發(fā)讀性能下降?!?/p>

三、C++標(biāo)準(zhǔn)庫 std::shared_mutex

我們文章開頭的測試出現(xiàn)了寫線程饑餓,那么 std::shared_mutex到底是公平性的還是非公平性的?還是說可以設(shè)置呢? 

1. C++ 標(biāo)準(zhǔn)的立場

C++ 標(biāo)準(zhǔn)僅定義 std::shared_mutex 的接口和行為規(guī)范(如“讀鎖共享,寫鎖獨占”),但 未規(guī)定鎖的獲取策略是否公平。這意味著: 

公平性(如讀/寫鎖的排隊順序、是否避免饑餓)由具體實現(xiàn)決定?!?/p>

不同平臺(如 Linux、Windows)或編譯器(如 GCC、Clang、MSVC)可能有不同行為?!?/p>

2. 常見實現(xiàn)的行為

Linux( GCC/libstdc++)  

底層通?;?nbsp;pthread_rwlock_t,默認(rèn)采用 讀優(yōu)先策略(允許新讀請求搶占等待的寫鎖),可能導(dǎo)致 寫線程饑餓。(不同 Linux 發(fā)行版或 glibc 版本可能有不同默認(rèn)行為,需查閱具體文檔) 

示例:若某線程持有讀鎖時,其他讀線程可以繼續(xù)獲取讀鎖,而寫線程可能長時間無法獲取鎖?!?/p>

Windows( MSVC)  

底層可能使用 SRWLock(Slim Reader/Writer Lock),其特性是:無優(yōu)先級保障的競爭式獲取,可能但不必然導(dǎo)致寫?zhàn)囸I。 當(dāng)鎖釋放時,等待的讀/寫線程通過競爭獲取鎖,不保證先到先得。 

寫線程可能因競爭失敗而饑餓,但實際行為依賴線程調(diào)度。 

四、解決方案:避免寫?zhàn)囸I的設(shè)計

1. 選擇支持寫優(yōu)先的讀寫鎖

手動實現(xiàn)(示例):  

class FairReadWriteLock {
    std::mutex mtx;
    std::condition_variable cv;
    int readers = 0;
    int writers_waiting = 0;
    bool writing = false;
    
public:
    void read_lock(){
        std::unique_lock lock(mtx);
        cv.wait(lock, [this] { 
            return !writing && writers_waiting == 0; // 無寫者或等待的寫者
        });
        readers++;
    }
    void read_unlock(){
        std::unique_lock lock(mtx);
        if (--readers == 0 && writers_waiting > 0) {
            cv.notify_one(); // 喚醒寫者
        }
    }
    void write_lock(){
        std::unique_lock lock(mtx);
        writers_waiting++;
        cv.wait(lock, [this] { 
            return !writing && readers == 0; // 無活動的讀/寫者
        });
        writers_waiting--;
        writing = true;
    }
    void write_unlock(){
        std::unique_lock lock(mtx);
        writing = false;
        cv.notify_all(); // 喚醒所有讀者和寫者
    }
};

效果:當(dāng)有寫者等待時,新讀者被阻塞,確保寫者最終執(zhí)行。 

2. 使用操作系統(tǒng)級公平鎖

Linux:通過 pthread_rwlockattr_setkind_np 設(shè)置 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP。  

pthread_rwlock_t rwlock;
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
pthread_rwlock_init(&rwlock, &attr);

3. 業(yè)務(wù)層限流

在讀邏輯中插入條件檢查,主動釋放鎖允許寫操作:(此方法依賴線程調(diào)度器實現(xiàn),可能緩解但無法徹底避免饑餓) 

void reader() {
    while (true) {
        {
            std::shared_lock lock(rw_mutex);
            // 讀操作...
        }
        std::this_thread::yield(); // 主動讓出CPU,增加寫者機(jī)會
    }
}

六、總結(jié)

寫請求能否執(zhí)行:取決于鎖實現(xiàn)的公平性策略。  

無公平性策略 → 可能饑餓(需業(yè)務(wù)層干預(yù))。  

寫優(yōu)先或公平隊列 → 可避免饑餓。   

責(zé)任編輯:武曉燕 來源: CppPlayer
相關(guān)推薦

2011-12-16 20:37:16

webOS

2020-01-13 14:16:32

區(qū)塊鏈應(yīng)用社交網(wǎng)絡(luò)

2011-11-03 09:13:52

UbuntuCanonical移動

2020-07-29 19:07:59

戴爾

2025-01-21 00:00:00

HashMap死循環(huán)數(shù)據(jù)損壞

2018-05-28 13:31:00

職場阿里巴巴

2012-11-12 09:26:06

.NET多線程

2014-09-09 17:23:54

移動互聯(lián)網(wǎng)App市場

2013-01-05 14:57:08

2013手機(jī)操作系統(tǒng)Ubuntu

2013-02-25 09:33:38

英特爾移動市場機(jī)會

2019-01-07 20:30:48

NoSQLNewSQL數(shù)據(jù)庫

2018-04-11 10:51:25

多線程進(jìn)程主線程

2021-01-11 11:14:35

微服務(wù)架構(gòu)調(diào)用

2015-10-22 15:56:27

RFID技術(shù)物聯(lián)網(wǎng)

2017-09-10 23:37:24

2010-05-25 10:19:18

谷歌蘋果

2015-07-29 15:05:01

2013-02-27 10:51:36

2011-04-14 13:27:53

Synchronize多線程

2023-11-09 07:23:57

Istio路由分析
點贊
收藏

51CTO技術(shù)棧公眾號