理解多執行緒(三)--互斥量
std::mutex
mutex就是互斥量的意思,在c++中使用互斥量需要包含#include
引入互斥量
之前瞭解了執行緒訪問公有資料是不安全的,所以使用互斥量來防治執行緒不安全的操作。
互斥量就是一個變數,只有兩種狀態,加鎖和解鎖。每一個互斥量管理一個公有資料,一個執行緒訪問公有資料後,互斥量加鎖,其他執行緒就不能訪問,等待之前的執行緒訪問完成解鎖後,才能訪問。
mutex分類
Mutex 系列類(四種)
std::mutex,基本Mutex 類。
std::recursive_mutex,遞迴 Mutex 類。
std::time_mutex,定時基本Mutex 類。
std::recursive_timed_mutex,定時遞迴 Mutex 類。
std::mutex
構造:不允許拷貝構造和move構造,初始化為解鎖狀態。
成員函式:
lock():加鎖,如果已經被其他執行緒加鎖了,則會阻塞
unlock():解鎖,線上程沒有獲得鎖是不能進行解鎖
try_lock():嘗試加鎖,如果已經被其他執行緒加鎖了,則不會阻塞,返回false。
mutex mu;
int x{ 0 };
mu.lock();
x++;
mu.unlock();
std::recursive_mutex
std::mutex只能進行一次上鎖解鎖操作,std::recursive_mutex允許一個執行緒對一個互斥量多次上鎖,但解鎖次數也必須相同。
recursive_mutex mu;
int x{ 0 };
mu.lock();mu.lock();
x++;
mu.unlock();mu.unlock();
std::timed_mutex
try_lock_for():
新增的成員函式,嘗試一直阻塞一個時間段加鎖,如果超過這個時間段沒有獲得鎖則返回false
try_lock_until():
新增的成員函式,嘗試在一個時間點前加鎖,如果這個時間段沒有獲得鎖則會返回false
recursive_mutex mu;
int x{ 0 };
if (mu.try_lock_for(std::chrono: :microseconds(10))) //嘗試阻塞10秒加鎖
{
++counter;
mu.unlock(); //解鎖
}
自動加鎖
上面的都是手動進行加鎖和解鎖,但有時如果人們加鎖後忘記了瞭解鎖,就會造成死鎖,所以c++11封裝了上面的加鎖解鎖操作,製作了std::lock_guard 與 std::unique_lock來進行自動的加鎖和解鎖操作。
std::lock_guard
std::lock_guard 在建構函式中進行加鎖,解構函式中進行解鎖。所以我們可以在棧上建立std::lock_guard,在生命週期結束後,自動解鎖。
int x {0 }; //原子變數
mutex mu; //互斥量
void fun()
{
std::lock_guard<std::mutex> lock(mu);
this_thread::sleep_for(std::chrono::microseconds(100));
x++;
}
int main()
{
for (size_t i = 0; i < 100; i++)
{
std::thread(fun).detach();
}
this_thread::sleep_for(std::chrono::microseconds(5000));
cout << x << endl;
system("pause");
return 0;
}
std::unique_lock
std::unique_lock比std::lock_guard功能更加強大,但是會耗費更多的時間和空間。