關於多執行緒的三兩事
阿新 • • 發佈:2021-07-21
https://www.cnblogs.com/idiotgroup/p/15032036.html
多執行緒一直是程式設計中的重要的工具,它可以分充分的利用硬體資源,是我們用更少的時間去完成更多的事情。在之前的部落格中,我有介紹了OpenMP的基本使用,OpenMP可以理解為多執行緒的一個合理和高效的一套抽象工具。這次,打算仔細的介紹多執行緒程式設計中的常見的概念和典型的案例。
典型的案例
說到多執行緒,最核心的問題就是保證資料的讀寫安全。為了達到此目的,我們需要多很多常見的資料結構做一些改造,從而適應多執行緒的場景。以下是我工作中比較常見到的一些使用場景:
- 執行緒池
- 讀寫鎖
- 訊息佇列
- ConcurrentCache
- PingPang Buffer
在具體介紹這些使用場景之前,我們還是需要了解需要使用到的一些基本的工具:互斥量、條件變數、原子操作等。
互斥量
互斥量,顧名思義,就是互斥的資料,一個執行緒持有的時候,其他執行緒就必須等待。
在C++11中,使用<mutex>
標頭檔案引入。以下是一個簡單的計數器的實現。
emit
函式通過mutex_
進行加鎖,使得同一時間僅有一個執行緒可以執行++ x_
的操作,從而保證了計數的正確性。
std::lock_guard
是個工具類,lck在構造時,呼叫了lock函式,在析構時呼叫了unlock,從而避免我們自行呼叫的時候忘記unlock。
#include <mutex>
#include <thread>
#include <iostream>
class Counter {
public:
Counter(): x_(0) {}
void emit() {
mutex_.lock();
++ x_;
mutex_.unlock();
// or
// std::lock_guard<std::mutex> lck(mutex_);
// ++ x_;
}
int count() {
return x_;
}
private:
int x_;
std::mutex mutex_;
};
int main() {
Counter c;
std::thread t1([&c]{
for (int i = 0; i < 10000000; ++ i) {
c.emit();
}
});
std::thread t2([&c]{
for (int i