接著上上節(jié) thread ,本節(jié)主要介紹mutex的內(nèi)容,練習(xí)代碼地址。
<mutex>:該頭文件主要聲明了與互斥量(mutex)相關(guān)的類,包括 std::mutex 系列類,std::lock_guard, std::unique_lock, 以及其他的類型和函數(shù)。
2、 <mutex>
mutex 頭文件中主要包含 Mutexes、lock 和相關(guān)的類型(Other types)和公共函數(shù)。
| (一)、 Mutexes |
| mutex | mutex互斥鎖是一個(gè)可鎖的對(duì)象,它被設(shè)計(jì)成在關(guān)鍵的代碼段需要獨(dú)占訪問時(shí)發(fā)出信號(hào),從而阻止具有相同保護(hù)的其他線程并發(fā)執(zhí)行并訪問相同的內(nèi)存位置。 |
| recursive_mutex | 遞歸互斥鎖是一個(gè)可鎖的對(duì)象,就像互斥一樣,但是允許同一個(gè)線程獲得對(duì)互斥對(duì)象的多個(gè)級(jí)別的所有權(quán)。 |
| timed_mutex | 定時(shí)的互斥信號(hào)是一個(gè)時(shí)間可鎖定的對(duì)象,旨在當(dāng)關(guān)鍵部分的代碼需要獨(dú)占訪問時(shí),就像一個(gè)普通互斥,但另外支持定時(shí)try-lock請(qǐng)求。 |
| recursive_timed_mutex | 一個(gè)遞歸的互斥對(duì)象結(jié)合的特點(diǎn)recursive_mutex timed_mutex到單個(gè)類的特性:它同時(shí)支持由一個(gè)線程獲取多個(gè)鎖級(jí)別也定時(shí)try-lock請(qǐng)求。 |
上面是 mutex頭文件中 mutexs中的相關(guān)類。上面類主要是幾種鎖對(duì)象。
-
std::mutex
- (constructor) 不允許拷貝;互斥對(duì)象不能被復(fù)制/移動(dòng),初始狀態(tài)為未鎖定。
default (1) constexpr mutex() noexcept;
copy [deleted] (2) mutex (const mutex&) = delete;
-
lock 鎖住互斥對(duì)象
- 如果互斥對(duì)象當(dāng)前沒有被任何線程鎖定,則調(diào)用線程鎖定它(從這一點(diǎn)開始,直到它的成員解鎖被調(diào)用,線程擁有互斥對(duì)象)。
- 如果互斥鎖當(dāng)前被另一個(gè)線程鎖定,則調(diào)用線程的執(zhí)行將被阻塞,直到其他線程解鎖(其他非鎖定線程繼續(xù)執(zhí)行它們)。
- 如果互斥鎖當(dāng)前被相同的線程所鎖定,調(diào)用此函數(shù),則會(huì)產(chǎn)生死鎖(未定義的行為)。
示例1:
// mutex::lock/unlock #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex std::mutex mtx; // mutex for critical section void print_thread_id (int id) { // critical section (exclusive access to std::cout signaled by locking mtx): mtx.lock(); std::cout << "thread #" << id << '\n'; mtx.unlock(); } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_thread_id,i+1); for (auto& th : threads) th.join(); return 0; } -
try_lock 試圖鎖定互斥鎖,不阻塞。
若互斥對(duì)象當(dāng)前沒有被任何線程鎖定,則調(diào)用線程鎖定它;
若互斥鎖當(dāng)前被另一個(gè)線程鎖定,則該函數(shù)失敗并返回false,沒有阻塞;若互斥鎖當(dāng)前被相同的線程所鎖定,調(diào)用此函數(shù),則會(huì)產(chǎn)生死鎖。
示例2:// mutex::try_lock example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex volatile int counter (0); // non-atomic counter std::mutex mtx; // locks access to counter void attempt_10k_increases () { for (int i=0; i<10000; ++i) { if (mtx.try_lock()) { // only increase if currently not locked: ++counter; mtx.unlock(); } } } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(attempt_10k_increases); for (auto& th : threads) th.join(); std::cout << counter << " successful increases of the counter.\n"; return 0; } unlock
解鎖互斥鎖,釋放所有權(quán)。native_handle
獲取本地處理,如果庫實(shí)現(xiàn)支持它,這個(gè)成員函數(shù)只存在于類互斥中。如果存在,它返回一個(gè)值用于訪問特定于實(shí)現(xiàn)的信息相關(guān)聯(lián)的對(duì)象。recursive_mutex
遞歸鎖基本函數(shù)同上,只是std::recursive_mutex 允許同一個(gè)線程對(duì)互斥量多次上鎖(即遞歸上鎖),來獲得對(duì)互斥量對(duì)象的多層所有權(quán),std::recursive_mutex 釋放互斥量時(shí)需要調(diào)用與該鎖層次深度相同次數(shù)的 unlock()。-
timed_mutex
timed_mutex鎖比較mutex所多了兩個(gè)成員函數(shù)try_lock_for 和 try_lock_until。-
try_lock_for
傳入時(shí)間段,在時(shí)間范圍內(nèi)未獲得所就阻塞住線程,如果在此期間其他線程釋放了鎖,則該線程可以獲得對(duì)互斥量的鎖,如果超時(shí),則返回 false。 -
try_lock_until
同上面的解釋,只是傳入?yún)?shù)為一個(gè)未來的一個(gè)時(shí)間點(diǎn)。
示例3:
// timed_mutex::try_lock_for example #include <iostream> // std::cout #include <chrono> // std::chrono::milliseconds #include <thread> // std::thread #include <mutex> // std::timed_mutex std::timed_mutex mtx; void fireworks () { // waiting to get a lock: each thread prints "-" every 200ms: while (!mtx.try_lock_for(std::chrono::milliseconds(2))) { std::cout << "-"; } // got a lock! - wait for 1s, then this thread prints "*" std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::cout << "*\n"; mtx.unlock(); } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) { threads[i] = std::thread(fireworks); } for (auto& th : threads) th.join(); return 0; }示例4:
// timed_mutex::try_lock_until example #include <iostream> // std::cout #include <chrono> // std::chrono::system_clock #include <thread> // std::thread #include <mutex> // std::timed_mutex #include <ctime> // std::time_t, std::tm, std::localtime, std::mktime std::timed_mutex cinderella; // gets time_point for next midnight: std::chrono::time_point<std::chrono::system_clock> midnight() { using std::chrono::system_clock; std::time_t tt = system_clock::to_time_t (system_clock::now()); struct std::tm * ptm = std::localtime(&tt); ++ptm->tm_mday; ptm->tm_hour=0; ptm->tm_min=0; ptm->tm_sec=0; return system_clock::from_time_t (mktime(ptm)); } void carriage() { if (cinderella.try_lock_until(midnight())) { std::cout << "ride back home on carriage\n"; cinderella.unlock(); } else std::cout << "carriage reverts to pumpkin\n"; } void ball() { cinderella.lock(); std::cout << "at the ball...\n"; cinderella.unlock(); } int main () { std::thread th1 (ball); std::thread th2 (carriage); th1.join(); th2.join(); return 0; } -
try_lock_for
recursive_timed_mutex
同上面分析,遞歸的時(shí)間鎖,允許同一個(gè)線程對(duì)互斥量多次上鎖(即遞歸上鎖), 不再贅述。
(二)、Locks 模板類
| lock_guard | Lock guard (class template ) | 模版類 |
| unique_lock | Unique lock (class template ) | 模版類 |
-
lock_guard
定義: template <class Mutex> class lock_guard;
鎖保護(hù)是一個(gè)通過將互斥對(duì)象保持鎖定來管理互斥對(duì)象的對(duì)象。
在構(gòu)造上,互斥對(duì)象被調(diào)用線程鎖定,并且在銷毀時(shí),互斥鎖被解鎖。它是最簡單的鎖,作為具有自動(dòng)持續(xù)時(shí)間的對(duì)象特別有用,直到它的上下文結(jié)束。這樣,它保證在拋出異常時(shí),可以正確地鎖定互斥對(duì)象。
注意,lock_guard對(duì)象不以任何方式管理互斥對(duì)象的生命周期:互斥對(duì)象的持續(xù)時(shí)間至少要延長到鎖定它的lock_guard的銷毀為止。
模板參數(shù) Mutex 代表互斥量類型,例如 std::mutex 類型,它應(yīng)該是一個(gè)基本的 BasicLockable 類型,標(biāo)準(zhǔn)庫中定義幾種基本的 BasicLockable 類型,分別 std::mutex, std::recursive_mutex, std::timed_mutexstd::recursive_timed_mutex 以及 std::unique_lock。 (注:BasicLockable 類型的對(duì)象只需滿足兩種操作,lock 和 unlock,另外還有 Lockable 類型,在 BasicLockable 類型的基礎(chǔ)上新增了 try_lock 操作,因此一個(gè)滿足 Lockable 的對(duì)象應(yīng)支持三種操作:lock,unlock 和 try_lock;最后還有一種 TimedLockable 對(duì)象,在 Lockable 類型的基礎(chǔ)上又新增了 try_lock_for 和 try_lock_until 兩種操作,因此一個(gè)滿足 TimedLockable 的對(duì)象應(yīng)支持五種操作:lock, unlock, try_lock, try_lock_for, try_lock_until)。
構(gòu)造函數(shù)(constructor)
locking (1) explicit lock_guard (mutex_type& m);
adopting (2) lock_guard (mutex_type& m, adopt_lock_t tag);
copy deleted lock_guard (const lock_guard&) = delete;
(1)鎖定初始化:對(duì)象管理m,并鎖定它(通過調(diào)用m.lock())。
(2)采用初始化:對(duì)象管理m,它是已經(jīng)當(dāng)前被構(gòu)造線程鎖定的互斥對(duì)象。
(3)復(fù)制構(gòu)造: 刪除(lock_guard對(duì)象不能被復(fù)制/移動(dòng))。
注:lock_guard的對(duì)象保持鎖定并管理m(通過調(diào)用它的成員解鎖)來解鎖它,當(dāng)lock_guard的對(duì)象析構(gòu)的時(shí)候,mtx將會(huì)被解鎖。
示例5:
// constructing lock_guard with adopt_lock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock_guard, std::adopt_lock
std::mutex mtx; // mutex for critical section
void print_thread_id (int id) {
mtx.lock();
std::lock_guard<std::mutex> lck (mtx, std::adopt_lock);
std::cout << "thread #" << id << '\n';
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
-
unique_lock
定義: template <class Mutex> class unique_lock;
unique_lock與 lock_guard 類相似,但它提供了更好的上鎖和解鎖控制。unique_lock 對(duì)象以獨(dú)占所有權(quán)的方式(官方叫做unique ownership)管理 mutex 對(duì)象的上鎖和解鎖操作;獨(dú)占所有權(quán),就是沒有其他的 unique_lock 對(duì)象同時(shí)擁有某個(gè) mutex 對(duì)象的所有權(quán)。
unique_lock對(duì)象在析構(gòu)的時(shí)候一定保證互斥量為解鎖狀態(tài);因此它作為具有自動(dòng)持續(xù)時(shí)間的對(duì)象特別有用,因?yàn)樗WC在拋出異常時(shí),互斥對(duì)象被正確地解鎖。不過,注意unique_lock對(duì)象并不以任何方式管理互斥對(duì)象的生命周期:互斥對(duì)象的持續(xù)時(shí)間將延長至少直到unique_lock管理它的毀滅。
- 構(gòu)造函數(shù)(constructor):
default (1) unique_lock() noexcept;
locking (2) explicit unique_lock (mutex_type& m);
try-locking (3) unique_lock (mutex_type& m, try_to_lock_t tag);
deferred (4) unique_lock (mutex_type& m, defer_lock_t tag) noexcept;
adopting (5) unique_lock (mutex_type& m, adopt_lock_t tag);
locking for (6) template <class Rep, class Period>
unique_lock (mutex_type& m, const chrono::duration<Rep,Period>& rel_time);
locking until (7) template <class Clock, class Duration>
unique_lock (mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);
copy [deleted] (8) unique_lock (const unique_lock&) = delete;
move (9) unique_lock (unique_lock&& x);
下面我們來分別介紹以上各個(gè)構(gòu)造函數(shù):
(1) 默認(rèn)構(gòu)造函數(shù)
unique_lock 對(duì)象不管理任何 Mutex 對(duì)象m。
(2) locking 初始化
unique_lock 對(duì)象管理 Mutex 對(duì)象 m,并調(diào)用 m.lock() 對(duì) Mutex 對(duì)象進(jìn)行上鎖,如果其他 unique_lock 對(duì)象已經(jīng)管理了m,該線程將會(huì)被阻塞。
(3) try-locking 初始化
unique_lock 對(duì)象管理 Mutex 對(duì)象 m,并調(diào)用 m.try_lock() 對(duì) Mutex 對(duì)象進(jìn)行上鎖,但如果上鎖不成功,不會(huì)阻塞當(dāng)前線程。
(4) deferred 初始化
unique_lock 對(duì)象管理 Mutex 對(duì)象 m并不鎖住m。 m 是一個(gè)沒有被當(dāng)前線程鎖住的 Mutex 對(duì)象。
(5) adopting 初始化
unique_lock 對(duì)象管理 Mutex 對(duì)象 m, m 應(yīng)該是一個(gè)已經(jīng)被當(dāng)前線程鎖住的 Mutex 對(duì)象。(當(dāng)前unique_lock 對(duì)象擁有對(duì)鎖(lock)的所有權(quán))。
(6) locking 一段時(shí)間(duration)
新創(chuàng)建的 unique_lock 對(duì)象管理 Mutex 對(duì)象 m,通過調(diào)用 m.try_lock_for(rel_time) 來鎖住 Mutex 對(duì)象一段時(shí)間(rel_time)。
(7) locking 直到某個(gè)時(shí)間點(diǎn)(time point)
新創(chuàng)建的 unique_lock 對(duì)象管理 Mutex 對(duì)象m,通過調(diào)用 m.try_lock_until(abs_time) 來在某個(gè)時(shí)間點(diǎn)(abs_time)之前鎖住 Mutex 對(duì)象。
(8) 拷貝構(gòu)造 [被禁用]
unique_lock 對(duì)象不能被拷貝構(gòu)造。
(9) 移動(dòng)(move)構(gòu)造
新創(chuàng)建的 unique_lock 對(duì)象獲得了由 x 所管理的 Mutex 對(duì)象的所有權(quán)(包括當(dāng)前 Mutex 的狀態(tài))。調(diào)用 move 構(gòu)造之后, x 對(duì)象如同通過默認(rèn)構(gòu)造函數(shù)所創(chuàng)建的,就不再管理任何 Mutex 對(duì)象了。
示例6:
// unique_lock constructor example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock, std::unique_lock
// std::adopt_lock, std::defer_lock
std::mutex foo,bar;
void task_a () {
std::lock (foo,bar); // simultaneous lock (prevents deadlock)
std::unique_lock<std::mutex> lck1 (foo,std::adopt_lock);
std::unique_lock<std::mutex> lck2 (bar,std::adopt_lock);
std::cout << "task a\n";
// (unlocked automatically on destruction of lck1 and lck2)
}
void task_b () {
// foo.lock(); bar.lock(); // replaced by:
std::unique_lock<std::mutex> lck1, lck2;
lck1 = std::unique_lock<std::mutex>(bar,std::defer_lock);
lck2 = std::unique_lock<std::mutex>(foo,std::defer_lock);
std::lock (lck1,lck2); // simultaneous lock (prevents deadlock)
std::cout << "task b\n";
// (unlocked automatically on destruction of lck1 and lck2)
}
int main ()
{
std::thread th1 (task_a);
std::thread th2 (task_b);
th1.join();
th2.join();
return 0;
}
- 其他成員函數(shù)
| Lock/unlock | 上鎖和解鎖過程 | |
|---|---|---|
| lock | Lock mutex (public member function ) | 調(diào)用被托管的互斥對(duì)象的成員鎖 |
| try_lock | Lock mutex if not locked (public member function ) | 嘗試上鎖 |
| try_lock_for | Try to lock mutex during time span (public member function ) | 嘗試在時(shí)間段上鎖 |
| try_lock_until | Try to lock mutex until time point (public member function ) | 嘗試在時(shí)間點(diǎn)到之前上鎖 |
| unlock | Unlock mutex (public member function ) | 解鎖 |
| Modifiers | 修改 | |
|---|---|---|
| operator= | Move-assign unique_lock (public member function ) | 同move操作 |
| swap | Swap unique locks (public member function ) | 交換兩個(gè)互斥對(duì)象 |
| release | Release mutex (public member function ) | 釋放鎖 |
| Observers | 獲取操作 |
|---|---|
| owns_lock | Owns lock (public member function ) |
| lock | Return whether it owns a lock (public member function ) |
| mutex | Get mutex (public member function ) |
(1)std::unique_lock::lock
鎖定互斥對(duì)象,調(diào)用被托管的互斥對(duì)象的成員鎖。
對(duì)已經(jīng)被其他線程鎖定的互斥對(duì)象調(diào)用鎖,阻塞當(dāng)前線程(等待),直到鎖釋放。當(dāng)函數(shù)返回時(shí),對(duì)象在互斥鎖上擁有一個(gè)鎖,如果調(diào)用鎖定失敗,system_error異常。
示例7:
// unique_lock::lock/unlock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
std::mutex mtx; // mutex for critical section
void print_thread_id (int id) {
std::unique_lock<std::mutex> lck (mtx,std::defer_lock);
// critical section (exclusive access to std::cout signaled by locking lck):
lck.lock();
std::cout << "thread #" << id << '\n';
lck.unlock();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
(2)std::unique_lock::try_lock
如果互斥量沒有鎖定就鎖定;調(diào)用try_lock 管理mutex對(duì)象,并使用返回值設(shè)置擁有狀態(tài);如果擁有的狀態(tài)在調(diào)用前為真或者如果對(duì)象目前管理沒有互斥對(duì)象,函數(shù)拋出一個(gè)system_error異常。
示例8:
// unique_lock::try_lock example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
std::mutex mtx; // mutex for critical section
void print_star () {
std::unique_lock<std::mutex> lck(mtx,std::defer_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.try_lock())
std::cout << '*';
else
std::cout << 'x';
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<500; ++i)
threads.emplace_back(print_star);
for (auto& x: threads) x.join();
std::cout << "\n";
return 0;
}
(3) std::unique_lock::try_lock_for
template <class Rep, class Period>
bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);
在時(shí)間范圍span內(nèi)鎖定互斥鎖;調(diào)用try_lock_for管理時(shí)間的mutex對(duì)象,并使用返回值設(shè)置擁有狀態(tài);如果在調(diào)用之前擁有狀態(tài)已經(jīng)真或者如果對(duì)象目前管理沒有互斥對(duì)象,函數(shù)拋出一個(gè)system_error異常。
示例9:
// unique_lock::try_lock_for example
#include <iostream> // std::cout
#include <chrono> // std::chrono::milliseconds
#include <thread> // std::thread
#include <mutex> // std::timed_mutex, std::unique_lock, std::defer_lock
std::timed_mutex mtx;
void fireworks () {
std::unique_lock<std::timed_mutex> lck(mtx,std::defer_lock);
// waiting to get a lock: each thread prints "-" every 200ms:
while (!lck.try_lock_for(std::chrono::milliseconds(200))) {
std::cout << "-";
}
// got a lock! - wait for 1s, then this thread prints "*"
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "*\n";
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(fireworks);
for (auto& th : threads) th.join();
return 0;
}
(4)std::unique_lock::try_lock_until
同上面描述,傳入一個(gè)時(shí)間點(diǎn)而不是時(shí)間段。示例:同上改動(dòng),不再述。
(5)std::unique_lock::unlock
調(diào)用unlock對(duì)托管的mutex對(duì)象進(jìn)行解鎖,并將擁有的狀態(tài)設(shè)置為false;如果調(diào)用之前擁有狀態(tài)是錯(cuò)誤,函數(shù)拋出一個(gè)system_error異常與operation_not_permitted錯(cuò)誤條件。
示例10:
// unique_lock::lock/unlock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
std::mutex mtx; // mutex for critical section
void print_thread_id (int id) {
std::unique_lock<std::mutex> lck (mtx,std::defer_lock);
// critical section (exclusive access to std::cout signaled by locking lck):
lck.lock();
std::cout << "thread #" << id << '\n';
lck.unlock();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
(6) std::unique_lock::operator=
move (1) unique_lock& operator= (unique_lock&& x) noexcept;
copy [deleted] (2) unique_lock& operator= (const unique_lock&) = delete;
使用x的mutex對(duì)象替換掉當(dāng)前對(duì)象的mutex,同時(shí)獲取x的狀態(tài)。替換掉的x將不再有mutex對(duì)象,如果對(duì)象在調(diào)用之前對(duì)其托管的mutex對(duì)象擁有一個(gè)鎖,那么它的解鎖成員在被替換之前就被調(diào)用了。;unique_lock對(duì)象不能被復(fù)制。
示例11:
// unique_lock::operator= example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx; // mutex for critical section
void print_fifty (char c) {
std::unique_lock<std::mutex> lck; // default-constructed
lck = std::unique_lock<std::mutex>(mtx); // move-assigned
for (int i=0; i<50; ++i) { std::cout << c; }
std::cout << '\n';
}
int main ()
{
std::thread th1 (print_fifty,'*');
std::thread th2 (print_fifty,'$');
th1.join();
th2.join();
return 0;
}
(7) std::unique_lock::swap
與x交換內(nèi)容,包括托管的互斥對(duì)象和它們當(dāng)前擁有的狀態(tài)。
(8) std::unique_lock::release
返回一個(gè)指向托管的互斥對(duì)象的指針,并釋放對(duì)它的所有權(quán);調(diào)用后unique_lock不再管理mutex對(duì)象(像默認(rèn)構(gòu)造一樣);注意,該函數(shù)不會(huì)鎖定或釋放返回的互斥對(duì)象。
示例12:
// unique_lock::release example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx;
int count = 0;
void print_count_and_unlock (std::mutex* p_mtx) {
std::cout << "count: " << count << '\n';
p_mtx->unlock();
}
void task() {
std::unique_lock<std::mutex> lck(mtx);
++count;
print_count_and_unlock(lck.release());
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<10; ++i)
threads.emplace_back(task);
for (auto& x: threads) x.join();
return 0;
}
(9) std::unique_lock::owns_lock
返回unique_lock對(duì)象擁有的一個(gè)鎖。unique_lock鎖定一個(gè)mutex,在沒有解鎖或者釋放unique_lock之前返回為真,其他情況返回為假;是unique_lock::operator bool的別名。
示例13:
// unique_lock::operator= example
#include <iostream> // std::cout
#include <vector> // std::vector
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::try_to_lock
std::mutex mtx; // mutex for critical section
void print_star () {
std::unique_lock<std::mutex> lck(mtx,std::try_to_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.owns_lock())
std::cout << '*';
else
std::cout << 'x';
}
int main ()
{
std::vector<std::thread> threads;
for (int i=0; i<500; ++i)
threads.emplace_back(print_star);
for (auto& x: threads) x.join();
std::cout << "\n";
return 0;
}
(10) std::unique_lock::operator bool
同上面。
(11) std::unique_lock::mutex
返回一個(gè)指向托管的mutex對(duì)象的指針。注意unique_lock不釋放互斥對(duì)象管理的所有權(quán)。如果它擁有一個(gè)互斥鎖,它仍然是負(fù)責(zé)釋放它在某一時(shí)刻(像當(dāng)unique_lock被銷毀的時(shí)候)。
示例14:
// unique_lock::mutex example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock, std::defer_lock
class MyMutex : public std::mutex {
int _id;
public:
MyMutex (int id) : _id(id) {}
int id() {return _id;}
};
MyMutex mtx (101);
void print_ids (int id) {
std::unique_lock<MyMutex> lck (mtx);
std::cout << "thread #" << id << " locked mutex " << lck.mutex()->id() << '\n';
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_ids,i+1);
for (auto& th : threads) th.join();
return 0;
}
| (三)、Othertypes其他類型 |
| once_flag | Flag argument type for call_once (class ) | once_flag |
| adopt_lock_t | Type of adopt_lock (class ) | adopt_lock_t |
| defer_lock_t | Type of defer_lock (class ) | defer_lock_t |
| try_to_lock_t | Type of try_to_lock (class ) | try_to_lock_t |
-
once_flag
此類型的對(duì)象用作call_once的參數(shù)。
在不同的線程中使用相同的對(duì)象在不同的調(diào)用上調(diào)用call_once,如果同時(shí)調(diào)用,則會(huì)單個(gè)執(zhí)行。
它是一個(gè)不可復(fù)制的、不可移動(dòng)的、可構(gòu)造的類。struct once_flag {
constexpr once_flag() noexcept;
once_flag (const once_flag&) = delete;
once_flag& operator= (const once_flag&) = delete;
}; -
adopt_lock_t
這是一個(gè)空的類,用作adopt_lock的使用的類型。
向unique_lock或lock_guard的構(gòu)造函數(shù)傳遞使用過的鎖,使該對(duì)象不鎖定互斥對(duì)象,并假設(shè)它已經(jīng)被當(dāng)前線程鎖定。
struct defer_lock_t {}; // 空類,只是作為adopt_lock類型constexpr adopt_lock_t adopt_lock {};
定義adopt_lock 值用作對(duì)unique_lock或lock_guard的構(gòu)造函數(shù)的可能參數(shù)。
使用adopt_lock構(gòu)造unique_lock對(duì)象不鎖定構(gòu)建中的互斥對(duì)象,只是假設(shè)它已經(jīng)被當(dāng)前線程鎖定了;這個(gè)值是一個(gè)沒有狀態(tài)的編譯時(shí)常量,只是用來消除構(gòu)造函數(shù)簽名之間的歧義。
defer_lock_t
這是一個(gè)空類,用作延遲鎖的類型。
將延遲鎖傳遞給unique_lock的構(gòu)造函數(shù),使它不會(huì)在構(gòu)造上自動(dòng)鎖定互斥對(duì)象,初始化對(duì)象為不擁有鎖。
struct defer_lock_t {};
constexpr defer_lock_t defer_lock {};
定義defer_lock用于unique_lock的構(gòu)造函數(shù)的可能的參數(shù)。使用延遲鎖構(gòu)造的unique_lock對(duì)象不將互斥對(duì)象自動(dòng)鎖定在構(gòu)造上,并初始化它們不擁有鎖。同上面的一樣,這個(gè)值是一個(gè)沒有狀態(tài)的編譯時(shí)常量,它只是用來消除構(gòu)造函數(shù)簽名之間的歧義。try_to_lock_t
try_to_lock_t是用于try_to_lock類型的空類。
將try_to_lock傳遞給unique_lock的構(gòu)造函數(shù),使它通過調(diào)用它的try_lock成員來鎖定互斥對(duì)象,代替lock。
struct try_to_lock_t {};
constexpr try_to_lock_t try_to_lock {};
try_to_lock 用于unique_lock的構(gòu)造函數(shù)的可能的參數(shù);使用try_to_lock構(gòu)造的unique_lock對(duì)象試圖通過調(diào)用其try_lock成員而不是鎖成員來鎖定互斥對(duì)象。
(四)、mutex中的函數(shù)
| try_lock | Try to lock multiple mutexes (function template ) | 試鎖互斥量 |
| lock | Lock multiple mutexes (function template ) | 鎖 |
| call_once | Call function once (public member function ) | call_once |
-
try_lock
std::try_lock是一個(gè)模版函數(shù):
template <class Mutex1, class Mutex2, class... Mutexes>
int try_lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
使用try_lock成員函數(shù)(非阻塞)式的鎖定對(duì)象a,b...等。函數(shù)為每個(gè)參數(shù)調(diào)用try_lock成員函數(shù)(首先是a,然后是b,最后是cde中的其他函數(shù)),直到所有調(diào)用都是成功的,或者只要調(diào)用失敗(返回false或拋出異常)。如果函數(shù)結(jié)束是因?yàn)檎{(diào)用失敗,則對(duì)所有調(diào)用try_lock成功的對(duì)象調(diào)用解鎖,函數(shù)將返回鎖定失敗的對(duì)象的參數(shù)序號(hào)。沒有對(duì)參數(shù)列表中的其余對(duì)象執(zhí)行其他調(diào)用。
示例15:
// std::lock example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::try_lock
std::mutex foo,bar;
void task_a () {
foo.lock();
std::cout << "task a\n";
bar.lock();
// ...
foo.unlock();
bar.unlock();
}
void task_b () {
int x = try_lock(bar,foo);
if (x==-1) {
std::cout << "task b\n";
// ...
bar.unlock();
foo.unlock();
}
else {
std::cout << "[task b failed: mutex " << (x?"foo":"bar") << " locked]\n";
}
}
int main ()
{
std::thread th1 (task_a);
std::thread th2 (task_b);
th1.join();
th2.join();
return 0;
}
-
lock
std::lock同樣為一個(gè)模版函數(shù)
template <class Mutex1, class Mutex2, class... Mutexes>
void lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
鎖定所有的參數(shù)互斥對(duì)象,阻塞當(dāng)前調(diào)用線程;該函數(shù)使用一個(gè)未指定的調(diào)用序列來鎖定對(duì)象,該序列調(diào)用其成員鎖、try_lock和解鎖,以確保所有參數(shù)都被鎖定在返回(不產(chǎn)生任何死鎖)。
如果函數(shù)不能鎖定所有對(duì)象(例如,因?yàn)槠渲幸粋€(gè)內(nèi)部調(diào)用拋出異常),則函數(shù)首先解鎖所有成功鎖定的對(duì)象(如果有的話)。
示例16:
// std::lock example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock
std::mutex foo,bar;
void task_a () {
// foo.lock(); bar.lock(); // replaced by:
std::lock (foo,bar);
std::cout << "task a\n";
foo.unlock();
bar.unlock();
}
void task_b () {
// bar.lock(); foo.lock(); // replaced by:
std::lock (bar,foo);
std::cout << "task b\n";
bar.unlock();
foo.unlock();
}
int main ()
{
std::thread th1 (task_a);
std::thread th2 (task_b);
th1.join();
th2.join();
return 0;
}
-
call_once
std::call_once 公有模版函數(shù)
template <class Fn, class... Args>
void call_once (once_flag& flag, Fn&& fn, Args&&... args);
call_once調(diào)用將args 作為fn的參數(shù)調(diào)用fn,除非另一個(gè)線程已經(jīng)(或正在執(zhí)行)使用相同的flag調(diào)用執(zhí)行call_once。如果已經(jīng)有一個(gè)線程使用相同flag調(diào)用call_once,會(huì)使得當(dāng)前變?yōu)楸粍?dòng)執(zhí)行,所謂被動(dòng)執(zhí)行不執(zhí)行fn也不返回直到恢復(fù)執(zhí)行后返回。這這個(gè)時(shí)間點(diǎn)上所有的并發(fā)調(diào)用這個(gè)函數(shù)相同的flag都是同步的。
注意,一旦一個(gè)活躍調(diào)用返回了,所有當(dāng)前被動(dòng)執(zhí)行和未來可能的調(diào)用call_once相同相同的flag也還不會(huì)成為積極執(zhí)行。
示例17:
// call_once example
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::milliseconds
#include <mutex> // std::call_once, std::once_flag
int winner;
void set_winner (int x) { winner = x; }
std::once_flag winner_flag;
void wait_1000ms (int id) {
// count to 1000, waiting 1ms between increments:
for (int i=0; i<1000; ++i)
std::this_thread::sleep_for(std::chrono::milliseconds(1));
// claim to be the winner (only the first such call is executed):
std::call_once (winner_flag,set_winner,id);
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(wait_1000ms,i+1);
std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";
for (auto& th : threads) th.join();
std::cout << "winner thread: " << winner << '\n';
return 0;
}
本文主要將mutex頭文件相關(guān),下篇c++11 多線程(3)atomic總結(jié)