亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++中Semaphore內(nèi)核對象用法實(shí)例

 更新時(shí)間:2023年01月28日 18:32:27   投稿:shichen2014  
這篇文章主要介紹了C++中Semaphore內(nèi)核對象用法實(shí)例,有助于深入了解信號量(Semaphore)的基本用法,需要的朋友可以參考下

信號量 (semaphore) 是一種輕量的同步原件,用于制約對共享資源的并發(fā)訪問。在可以使用兩者時(shí),信號量能比條件變量更有效率。1

下面是在 www.open-std.org 對 C++20 semaphore 的一點(diǎn)介紹內(nèi)容。(semaphores、latch、barrier)

Semaphores are lightweight synchronization primitives used to constrain concurrent access to a shared resource. They are widely used to implement other synchronization primitives and, whenever both are applicable, can be more efficient than condition variables.
A counting semaphore is a semaphore object that models a non-negative resource count. A binary semaphore is a semaphore object that has only two states, also known as available and unavailable. [ Note: A binary semaphore should be more efficient than a counting semaphore with a unit magnitude count. – end note ]

信號量是用于限制對共享資源的并發(fā)訪問的輕量級同步原語。它們被廣泛應(yīng)用于實(shí)現(xiàn)其他同步原語,并且,只要兩者都適用,就可以比條件變量更有效。

計(jì)數(shù)信號量是模擬非負(fù)資源計(jì)數(shù)的信號量對象。二進(jìn)制信號量是一個只有兩種狀態(tài)的信號量對象,也稱為可用和不可用。[注意:二進(jìn)制信號量應(yīng)該比使用單位數(shù)量級計(jì)數(shù)的計(jì)數(shù)信號量更有效。–尾注]

cppreference.com 中的標(biāo)準(zhǔn)庫頭文件 <semaphore> 中也給出了詳細(xì)定義。3。

C++20 中提供了兩個信號量類。(其實(shí)binary_semaphore僅僅是counting_semaphore的一個特例。)

信號量類名含義
counting_semaphore實(shí)現(xiàn)非負(fù)資源計(jì)數(shù)的信號量
binary_semaphore僅擁有二個狀態(tài)的信號量

cppreference.com中給出的關(guān)于semaphore的定義如下:

// 概要
namespace std {
  template<ptrdiff_t LeastMaxValue = /* 實(shí)現(xiàn)定義 */>
    class counting_semaphore;
 
  using binary_semaphore = counting_semaphore<1>;
}

// 類模板 std::counting_semaphore
namespace std {
  template<ptrdiff_t LeastMaxValue = /* 實(shí)現(xiàn)定義 */>
  class counting_semaphore {
  public:
    static constexpr ptrdiff_t max() noexcept;
 
    constexpr explicit counting_semaphore(ptrdiff_t desired);
    ~counting_semaphore();
 
    counting_semaphore(const counting_semaphore&) = delete;
    counting_semaphore& operator=(const counting_semaphore&) = delete;
 
    void release(ptrdiff_t update = 1);
    void acquire();
    bool try_acquire() noexcept;
    template<class Rep, class Period>
      bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
 
  private:
    ptrdiff_t counter;          // 僅用于闡釋
  };
}

std::counting_semaphore4

counting_semaphore 是一個輕量同步元件,能控制對共享資源的訪問。不同于 std::mutex 、 counting_semaphore 允許同一資源有多于一個同時(shí)訪問,至少允許 LeastMaxValue 個同時(shí)的訪問者若LeastMaxValue 為負(fù)則程序?yàn)橹嚇?gòu)。
binary_semaphore 是 std::counting_semaphore 的特化的別名,其 LeastMaxValue 為 1 。實(shí)現(xiàn)可能將 binary_semaphore 實(shí)現(xiàn)得比 std::counting_semaphore 的默認(rèn)實(shí)現(xiàn)更高效。
counting_semaphore 含有由構(gòu)造函數(shù)初始化的內(nèi)部計(jì)數(shù)器。由調(diào)用 acquire() 與相關(guān)方法減少此計(jì)數(shù)器,而它通過調(diào)用 release() 增加。計(jì)數(shù)器為零時(shí), acquire() 阻塞該計(jì)數(shù)器直至它增加,但 try_acquire() 不阻塞; try_acquire_for() 與 try_acquire_until() 阻塞直至計(jì)數(shù)器增加或到達(dá)時(shí)限。
類似 std::condition_variable 的 wait() , counting_semaphore 的 try_acquire() 可能虛假地失敗。
std::counting_semaphore的主要接口

接口含義
release增加內(nèi)部計(jì)數(shù)器并除阻獲取者
acquire減少內(nèi)部計(jì)數(shù)器或阻塞到直至能如此
try_acquire嘗試減少內(nèi)部計(jì)數(shù)器而不阻塞
try_acquire_for嘗試減少內(nèi)部計(jì)數(shù)器,至多阻塞一段時(shí)長
try_acquire_until嘗試減少內(nèi)部計(jì)數(shù)器,阻塞直至一個時(shí)間點(diǎn)
max返回內(nèi)部計(jì)數(shù)器的最大可能值(靜態(tài),常量)

注解

如其名所示, LeastMaxValue 是最小的最大值,而非實(shí)際最大值。從而 max() 能產(chǎn)生大于 LeastMaxValue 的值。

不同于 std::mutex , counting_semaphore 不捆綁到執(zhí)行線程——能在不同于釋放信號量的線程獲取該信號量。能同時(shí)進(jìn)行 counting_semaphore 上的所有操作而無需聯(lián)系到任何特定的執(zhí)行線程,除了不能同時(shí)執(zhí)行,但能在一個不同的線程上執(zhí)行析構(gòu)函數(shù)。

信號量亦常用于發(fā)信/提醒而非互斥,通過初始化該信號量為 ?0? 從而阻塞嘗試 acquire() 的接收者,直至提醒者通過調(diào)用 release(n) “發(fā)信”。在此方面可把信號量當(dāng)作 std::condition_variable 的替用品,通常它有更好的性能。

semaphore、mutex、condition_variable的區(qū)別

信號量 (semaphore) 是一種輕量的同步原件,用于制約對共享資源的并發(fā)訪問。在可以使用兩者時(shí),信號量能比條件變量更有效率。

互斥(mutex)算法避免多個線程同時(shí)訪問共享資源。這會避免數(shù)據(jù)競爭,并提供線程間的同步支持。

條件變量(condition_variable)是允許多個線程相互交流的同步原語。它允許一定量的線程等待(可以定時(shí))另一線程的提醒,然后再繼續(xù)。條件變量始終關(guān)聯(lián)到一個互斥。

1: semaphore對acquire和release操作沒有限制,可以在不同線程操作;可以僅在線程A里面acquire,僅在線程B里面release。
mutex的lock和unlock必須在同一個線程配對使用;也就是說線程A內(nèi)mutex如果lock了,必須在線程A內(nèi)unlock,線程B內(nèi)lock了,也必須在線程B內(nèi)unlock。
2: semaphore和mutex是可以獨(dú)立使用的;condition_variable必須和mutex配對使用。
3: semaphore一般用于控制多個并發(fā)資源的訪問或者控制并行數(shù)量;mutex一般是起到同步訪問一個資源的作用。同一時(shí)刻,mutex保護(hù)的資源只能被一個線程訪問;semaphore的保護(hù)對象上面是可以有多個線程在訪問的。mutex是同步,semaphore是并行。
4: 由于condition_variable和mutex結(jié)合使用,condition_variable更多是為了通知、順序之類的控制。
5: C++語言中的mutex、semaphore、condition和系統(tǒng)級的概念不同。都是線程級別的,也就是不能跨進(jìn)程控制的。要區(qū)別于windows api的 mutex、semaphore、event。windows系統(tǒng)上這幾個api創(chuàng)建有名對象時(shí),是進(jìn)程級別的。

C++中Semaphore內(nèi)核對象的用法

// Semaphore.cpp : 定義控制臺應(yīng)用程序的入口點(diǎn)。?
//?
?
#include "stdafx.h"?
#include <Windows.h>?
#include <process.h>??
?
HANDLE g_hSemaphore;?
DWORD g_nConut1 = 0;?
DWORD g_nConut2 = 0;?
unsigned __stdcall ThreadProc1( void* pArguments )?
{?
??? ::WaitForSingleObject(g_hSemaphore, INFINITE);?
??? for (int i=0;i<10000;i++)?
??? {?
??????? g_nConut1++;?
??????? g_nConut2++;?
??? }?
??? ::ReleaseSemaphore(g_hSemaphore, 1, NULL);?
??? printf("ThreadProc1\n");?
??? return 0;?
}?
?
unsigned __stdcall ThreadProc2( void* pArguments )?
{?
??? ::WaitForSingleObject(g_hSemaphore, INFINITE);?
??? for (int i=0;i<10000;i++)?
??? {?
??????? g_nConut1++;?
??????? g_nConut2++;?
??? }?
??? ::ReleaseSemaphore(g_hSemaphore, 1, NULL);?
??? printf("ThreadProc2\n");?
??? return 0;?
}?
?
unsigned __stdcall ThreadProc3( void* pArguments )?
{?
??? ::WaitForSingleObject(g_hSemaphore, INFINITE);?
??? for (int i=0;i<10000;i++)?
??? {?
??????? g_nConut1++;?
??????? g_nConut2++;?
??? }?
??? ::ReleaseSemaphore(g_hSemaphore, 1, NULL);?
??? printf("ThreadProc3\n");?
??? return 0;?
}?
int _tmain(int argc, _TCHAR* argv[])?
{?
??? g_hSemaphore = ::CreateSemaphore(NULL, 2, 2, NULL);?
??? HANDLE hThread[3];?
??? hThread[0] = (HANDLE)::_beginthreadex(NULL, 0, ThreadProc1, NULL, 0, NULL);?
??? hThread[1] = (HANDLE)::_beginthreadex(NULL, 0, ThreadProc2, NULL, 0, NULL);?
??? hThread[2] = (HANDLE)::_beginthreadex(NULL, 0, ThreadProc3, NULL, 0, NULL);?
?
??? ::WaitForMultipleObjects(2,hThread,TRUE, INFINITE);?
??? printf("g_count1=%d\n", g_nConut1);?
??? printf("g_count2=%d\n", g_nConut2);?
??? printf("main finished.\n");?
??? return 0;?
}

linux信號量semaphore的幾種使用方法

以下提到的幾種應(yīng)用方式,下面都有示例代碼。

注意:有個點(diǎn)容易遺忘的:當(dāng)semop的實(shí)參sops設(shè)置>0的操作時(shí),一般要給這個op動作添加SEM_UNDO標(biāo)志,詳情可參考另一篇博文:linux線程通信之信號量。

應(yīng)用情景一:用信號量打造一個二值信號量(互斥量),也即:任何時(shí)刻只允許一個線程訪問共享資源。P操作用于占用資源,V操作代表釋放資源。

使用信號量,關(guān)鍵是要知道semop函數(shù)的特性:

① semop函數(shù)的第二形參sops可以以數(shù)組地址的形式輸入多個動作(稱為動作集),man手冊上講,semop函數(shù)會按照sops數(shù)組的順序、原子性的執(zhí)行動作集中的動作,要么一個都不執(zhí)行,要么全部執(zhí)行。手冊上說的這句話我覺得是有點(diǎn)問題的,“要么全部執(zhí)行”這句話實(shí)際上有個例外:如果動作集中某個動作設(shè)置的條件(如等待0)會使得線程堵塞在本函數(shù)中(或者本函數(shù)出錯返回)的話,那么后面的動作就只能等解除堵塞之后才能被執(zhí)行(堵塞時(shí)),或者得不到執(zhí)行(semop出錯返回時(shí))。
② 如果在某時(shí)刻有多個線程都在等待互斥信號量的使用權(quán),那么一旦占用該互斥量的線程把它釋放后,這多個等待的線程中,只能有一個線程被解除堵塞

ps:當(dāng)無法獲得信號量資源時(shí),semop到底是堵塞,還是設(shè)置錯誤并返回,取決于第四參數(shù)是否或了IPC_NOWAIT標(biāo)志。

方法1:

步驟:
(1) 把信號量的值初始化為0(創(chuàng)建信號量之后默認(rèn)值就是0,該步驟不做也行)
(2) P操作,用semop函數(shù)設(shè)置線程等待信號量的值semval為0,若不為0則堵塞或報(bào)錯;然后用semop函數(shù)把信號量的值+1(也即:semval為0時(shí)可以立即通過,否則就要等待)。本步驟中的兩個動作,必須通過semop的實(shí)參一次把兩個動作都輸入進(jìn)去,而不能分別調(diào)用兩次semop來實(shí)現(xiàn)。
(3) V操作,用semop函數(shù)設(shè)置信號值-1,注意:只有信號量值≥abs(-1)時(shí),才能夠立即減1后立即返回,否則本線程又得等待,直到信號量值≥abs(-1)。當(dāng)然,因?yàn)镻操作已經(jīng)把信號量值+1了,所以這里信號量值肯定是≥abs(-1)。

分析:①整個程序中首次執(zhí)行P操作的時(shí)候,情況是怎樣的?看步驟(2),設(shè)置本線程為等待semval變?yōu)?,因?yàn)閟emval被初始化為0了,所以semop會立即返回或者繼續(xù)執(zhí)行形參指定的下一個動作:把semval+1。+1這種動作永不堵塞,于是本線程將繼續(xù)向下執(zhí)行開始訪問共享資源。
    ②當(dāng)某個線程A執(zhí)行P之后,尚未V之前,又有另個線程B開始執(zhí)行P了,情況是怎樣的?還是看步驟(2),設(shè)置本線程B為等待semval變?yōu)?,因?yàn)榫€程A已經(jīng)把semval設(shè)為1了,于是線程B被堵塞或報(bào)錯。
    ③ 為什么步驟(2)中不允許把等待0和+1這兩個動作分別用兩次semop來實(shí)現(xiàn)?試想這樣一種情形:semval初始化為0,當(dāng)進(jìn)程A等待0時(shí),發(fā)現(xiàn)確實(shí)是0,于是繼續(xù)向下執(zhí)行semop的+1(進(jìn)而開始訪問共享資源),這時(shí)發(fā)生了進(jìn)程/線程調(diào)度,切入了線程B,線程B恰好也要執(zhí)行P操作,等待semval變?yōu)?,也發(fā)現(xiàn)確實(shí)是0,于是繼續(xù)向下執(zhí)行semop的+1 (進(jìn)而開始訪問共享資源),顯然,沒有達(dá)到預(yù)想的互斥的效果。semop函數(shù)提供了一種機(jī)制,把多個動作(稱為動作集)通過形參一次性傳入進(jìn)去之后,操作系統(tǒng)可以保證,這些動作要么一個也不執(zhí)行,要么全部被執(zhí)行(除非:如果某個動作設(shè)置的條件會堵塞線程時(shí),等堵塞解除后,后面的動作才會執(zhí)行),這就杜絕了這一問題。

方法2:

步驟:
① 用semctl或者semop把信號量值初始化為1
② P操作,用semop函數(shù)設(shè)置線程等待,直到semval≥abs(-1)才解除等待(也即,semval≥1時(shí)可以立即通過,否則就要等待);
③ V操作,用semop函數(shù)設(shè)置semval+1

分析:①整個程序中首次執(zhí)行P操作的時(shí)候,情況是怎樣的?看步驟(2),因?yàn)閟emval被初始化為1了,故本次P操作并不堵塞或出錯,而是把semval-1后直接返回,P操作完成后semval就變成0了;

 ②當(dāng)某個線程A執(zhí)行P之后,尚未V之前,又有另個線程B開始執(zhí)行P了,情況是怎樣的?還是看步驟(2),設(shè)置本線程B為等待等待semval≥abs(-1),因?yàn)榫€程A的P已經(jīng)把semval設(shè)為0了,于是線程B被堵塞或報(bào)錯;

應(yīng)用情景二:例如,某個資源最多只允許5個線程同時(shí)訪問

這種應(yīng)用場景的一個更貼近生活的例子:某開水房的水管上(這跟水管就是個共享資源),只有5個水龍頭,那么這跟水管最多只允許5個人同時(shí)打水。每來一個人打水,信號量減1,每走一個人,信號量+1,也即:只要空閑水龍頭的數(shù)目(信號量)≥1,就可以放人進(jìn)來打水,否則,都得排隊(duì)等。

這種應(yīng)用情景的處理方法,和上面提到的方法(2)是一樣的,唯一的區(qū)別就是初始化時(shí),要信號量的值初始化為n:

方法3:

步驟:
① 用semctl或者semop把信號量值初始化為5;
② P操作,用semop函數(shù)設(shè)置線程等待,直到semval≥abs(-1)才解除等待(也即,semval≥1時(shí)可以立即通過,否則就要等待);

③ V操作,用semop函數(shù)設(shè)置semval+1;

分析: 程序把信號量值初始化為5以后,同時(shí)有13個線程發(fā)起了P操作,請求訪問共享資源,這時(shí)情況是怎樣的?名義上是同時(shí),實(shí)際上在該信號量的信息維護(hù)鏈表中,發(fā)起P操作的線程仍然是有先后的,第一名開始執(zhí)行P,信號量發(fā)現(xiàn)自己的值是5,可以滿足第一名提出的semval≥abs(-1)無需等待條件,于是第一名無需等待,P操作直接返回(<的操作返回時(shí)會把信號量值減掉),從而可以訪問共享資源了;第二名線程開始執(zhí)行P操作,信號量發(fā)現(xiàn)自己是4,也可以滿足不等待的條件semval≥abs(-1)······,也即,前5名線程執(zhí)行P操作,完全不用等待,都可以直接獲得共享資源,而其余的13-7=7個線程執(zhí)行P操作會被阻塞。前5名當(dāng)中,一旦有其中一個用完了資源并釋放了資源(執(zhí)行V操作)之后,那么第6名線程就會解除等待,從而獲得共享資源的訪問權(quán)。

希望本文所述對大家的C++程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • 詳解C++?轉(zhuǎn)換的非正式分類

    詳解C++?轉(zhuǎn)換的非正式分類

    C++?正式分類方法是直接按語法分類,分為:隱式轉(zhuǎn)換和顯示轉(zhuǎn)換。這篇文章主要介紹了C++?轉(zhuǎn)換的非正式分類,需要的朋友可以參考下
    2022-01-01
  • C++中一維數(shù)組與指針的關(guān)系詳細(xì)總結(jié)

    C++中一維數(shù)組與指針的關(guān)系詳細(xì)總結(jié)

    以下是對C++中一維數(shù)組與指針的關(guān)系進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下
    2013-09-09
  • C語言學(xué)習(xí)之函數(shù)知識總結(jié)

    C語言學(xué)習(xí)之函數(shù)知識總結(jié)

    函數(shù)是一組一起執(zhí)行一個任務(wù)的語句。每個?C?程序都至少有一個函數(shù),即主函數(shù)?main()?,所有簡單的程序都可以定義其他額外的函數(shù)。本文就為大家詳細(xì)講講C語言中函數(shù)的相關(guān)知識點(diǎn),希望有所幫助
    2022-07-07
  • C++中try throw catch異常處理的用法示例

    C++中try throw catch異常處理的用法示例

    這篇文章主要給大家介紹了關(guān)于C++中try throw catch異常處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • C++程序設(shè)計(jì)-五子棋

    C++程序設(shè)計(jì)-五子棋

    本文將以簡單的存儲結(jié)構(gòu)及簡單的運(yùn)算,條件語句,分支語句,循環(huán)語句結(jié)合,帶來一個雙人對戰(zhàn)版五子棋,這是一個簡單的模型,實(shí)現(xiàn)了五子棋最最基本的功能。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • C++面試八股文之override和finial關(guān)鍵字有何作用

    C++面試八股文之override和finial關(guān)鍵字有何作用

    C++11中的override和final關(guān)鍵字是為了增強(qiáng)代碼的編譯時(shí)類型檢查和面向?qū)ο笤O(shè)計(jì)中的繼承機(jī)制,下面這篇文章主要給大家介紹了關(guān)于C++面試八股文之override和finial關(guān)鍵字有何作用的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • C語言以數(shù)據(jù)塊的形式讀寫文件實(shí)例代碼

    C語言以數(shù)據(jù)塊的形式讀寫文件實(shí)例代碼

    本文主要介紹C語言中以數(shù)據(jù)塊的形式讀寫文件,這里提供了實(shí)例代碼舉例說明,有需要的小伙伴可以參考下
    2016-07-07
  • C++標(biāo)準(zhǔn)庫中sstream與strstream的區(qū)別詳細(xì)解析

    C++標(biāo)準(zhǔn)庫中sstream與strstream的區(qū)別詳細(xì)解析

    以下是對C++標(biāo)準(zhǔn)庫中sstream與strstream的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-09-09
  • C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別

    C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別

    本文主要介紹了C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • C語言算法的定義及分析詳解

    C語言算法的定義及分析詳解

    這篇文章主要為大家詳細(xì)介紹了C語言算法的定義及分析,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論