c 常用多執行緒知識

2021-06-20 01:32:39 字數 2289 閱讀 8913

多執行緒主題本身是個大課題,簡單起見,將c++多執行緒程式設計的挑戰歸結於對資源的同步訪問。這裡的資源可以指單個變數,乙個類,或者說乙個執行緒產生的東西另外乙個執行緒去消費。對此,c++缺乏語言層面的支援。下面介紹下常見的同步訪問型別。

1. 整型值的同步訪問,經典的例子就是遞增或者遞減變數,比如++i 等於是i=i+1,對i遞增有如下幾個步驟:從記憶體中取值,將該值加1,最後將新值儲存到i的記憶體位置,這個過程成為"讀-改-寫"(rmw,read-modify-write), 很顯然該過程非原子的,是可以被其他執行緒中斷的。各作業系統提供了執行緒安全的操作方式,這種做法可以節約可觀的效能開銷。

以下為乙個簡單的原子型別包裝,原子型別常用於多執行緒引用計數。

class atomicnumber

long get()

long set(int n)

long inc()

long dec()

long add(int n)

long sub(int n)

bool cas(long cmp,long newv)

private:

volatile long mvalue;

};

2. 對**塊的同步訪問:臨界區,對大多數同步需求來說,單個原子操作不夠,他們往往需要對某個**塊獨佔的訪問,這也是我們最廣泛使用的同步方式,也是相對來說代價高昂的一種方式,但是這種方式使用簡單,不容易出錯。這種方式往往會伴隨核心切換,這種切換代價高昂。下面介紹一種特殊的基於輪詢的一種互斥體,簡單來說輪詢就是不斷反覆測試來等待某個條件的改變,稱之為自旋互斥體,輪詢意味著會吞噬cpu週期。但是某些場合還是非常適合使用這種自旋互斥體的,比如臨界區非常短小,資源競爭也不那麼激烈的時候,這種方式就很適合。下面給出乙個來自於facebook開源的超輕量的自旋鎖,該實現的效能調優點就是先輪詢等待最多4000次,超過4000次則主動交出cpu,防止競爭激烈的時候大量占用cpu。

class sleeper

void wait() else

;nanosleep(&ts, null);}}

};class spinlock

void lock()

while(!lock_.cas(free,locked));

}void unlock()

private:

enum ;

atomicnumber lock_;

};

簡單的方式:

使用你使用平台提供的鎖(互斥、臨界區域,或等效)。這從概念上不難理解,使用上更簡單。你無需擔心排列問題,庫或os會替你解決。使用鎖的唯一問題就是慢(這裡的「慢」是相對而言的:一般應用,它的速度足夠了)。

困難的方式:

使用無鎖的方式,為什麼不是每個人都使用無鎖程式設計呢?嗯,它不那麼容易用對。任何情況下,不管每個執行緒在做什麼,你必須很小心,絕不能破壞資料。但更難的是順序相關的保證。在多核環境,**的執行順序可能並不是我們表面看到編碼順序,因為編譯器和cpu會進行各種優化。

考慮這個例子(a和b從0開始):

thread a thread b

b = 42

a = 1

print(a)

print(b)

執行緒b可能會輸出的一組值是什麼呢?有可能是,,和, , 中的任何一組,這裡有兩種情況會導致亂序,一是編譯器優化亂序,二是cpu執行亂序,為了保障這種順序一致性就必須了解有什麼手段可以保障,答案就是記憶體屏障

分享兩個實現,乙個是單一生產者單一消費者佇列,乙個是多生產者多消費者佇列

lock-free 的訊息佇列,這是網路程式中經常用到的方式,實現這些佇列的核心就是 atomic, 其中需要注意的就是記憶體訪問的順序控制,解決偽共享(false sharing)以及無鎖演算法。

4:linux 2.6.22以後的核心版本中增加了eventfd,可以用來實現執行緒間的等待通知機制,eventfd使用的仍然是「一切皆檔案」的思想,建立好的eventfd可以通過epoll來監聽讀寫事件,結合訊息佇列,可以實現高效的執行緒間通訊。比如執行緒a準備好了資料,作為生產者push進佇列,通過eventfd通知執行緒b,執行緒b監聽到讀事件後,會被喚醒,執行緒b作為消費者從訊息隊裡中pop訊息

5:根據需求選擇合適的同步或者通訊方式

多執行緒知識

同步 多個任務依次按順序執行 非同步 多個任務可以時執行 程序 乙個正在執行的應用程式就是乙個程序,為應用開闢記憶體空間 執行緒 乙個程序可以有多個執行緒,是程序的基本執行單元,執行應用的 任務 nsthread 建立執行緒 方法一 物件方法 nsthread thread nsthread all...

c 基礎知識 多執行緒

執行緒被定義為程式的執行路徑。每個執行緒都定義了乙個獨特的控制流。如果您的應用程式涉及到複雜的和耗時的操作,那麼設定不同的執行緒執行路徑往往是有益的,每個執行緒執行特定的工作。執行緒是輕量級程序。乙個使用執行緒的常見例項是現代作業系統中並行程式設計的實現。使用執行緒節省了 cpu 週期的浪費,同時提...

C 多執行緒 非同步執行緒 執行緒池相關知識

執行緒池threadpool類會在需要時增減池中線程的執行緒數,直到最大的執行緒數。池中的最大執行緒數是可配置的。在雙核cpu中,預設設定為1023個工作執行緒和1000個i o執行緒。也可以指定在建立執行緒池時應立即啟動的最小執行緒數,以及執行緒池,中可用的最大執行緒數。如果有更多的作業要處理,執...