接著上上節(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互斥鎖是一個可鎖的對象,它被設(shè)計成在關(guān)鍵的代碼段需要獨(dú)占訪問時發(fā)出信號肤频,從而阻止具有相同保護(hù)的其他線程并發(fā)執(zhí)行并訪問相同的內(nèi)存位置叹括。 |
recursive_mutex | 遞歸互斥鎖是一個可鎖的對象,就像互斥一樣宵荒,但是允許同一個線程獲得對互斥對象的多個級別的所有權(quán)汁雷。 |
timed_mutex | 定時的互斥信號是一個時間可鎖定的對象,旨在當(dāng)關(guān)鍵部分的代碼需要獨(dú)占訪問時,就像一個普通互斥,但另外支持定時try-lock請求。 |
recursive_timed_mutex | 一個遞歸的互斥對象結(jié)合的特點(diǎn)recursive_mutex timed_mutex到單個類的特性:它同時支持由一個線程獲取多個鎖級別也定時try-lock請求报咳。 |
上面是 mutex頭文件中 mutexs中的相關(guān)類侠讯。上面類主要是幾種鎖對象。
-
std::mutex
- (constructor) 不允許拷貝暑刃;互斥對象不能被復(fù)制/移動厢漩,初始狀態(tài)為未鎖定。
default (1) constexpr mutex() noexcept;
copy [deleted] (2) mutex (const mutex&) = delete;
-
lock 鎖住互斥對象
- 如果互斥對象當(dāng)前沒有被任何線程鎖定岩臣,則調(diào)用線程鎖定它(從這一點(diǎn)開始溜嗜,直到它的成員解鎖被調(diào)用,線程擁有互斥對象)架谎。
- 如果互斥鎖當(dāng)前被另一個線程鎖定炸宵,則調(diào)用線程的執(zhí)行將被阻塞,直到其他線程解鎖(其他非鎖定線程繼續(xù)執(zhí)行它們)狐树。
- 如果互斥鎖當(dāng)前被相同的線程所鎖定,調(diào)用此函數(shù)鸿脓,則會產(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 試圖鎖定互斥鎖,不阻塞野哭。
若互斥對象當(dāng)前沒有被任何線程鎖定在塔,則調(diào)用線程鎖定它;
若互斥鎖當(dāng)前被另一個線程鎖定拨黔,則該函數(shù)失敗并返回false蛔溃,沒有阻塞;若互斥鎖當(dāng)前被相同的線程所鎖定,調(diào)用此函數(shù)贺待,則會產(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)支持它,這個成員函數(shù)只存在于類互斥中哪工。如果存在,它返回一個值用于訪問特定于實(shí)現(xiàn)的信息相關(guān)聯(lián)的對象奥此。recursive_mutex
遞歸鎖基本函數(shù)同上,只是std::recursive_mutex 允許同一個線程對互斥量多次上鎖(即遞歸上鎖)雁比,來獲得對互斥量對象的多層所有權(quán)稚虎,std::recursive_mutex 釋放互斥量時需要調(diào)用與該鎖層次深度相同次數(shù)的 unlock()。-
timed_mutex
timed_mutex鎖比較mutex所多了兩個成員函數(shù)try_lock_for 和 try_lock_until偎捎。-
try_lock_for
傳入時間段蠢终,在時間范圍內(nèi)未獲得所就阻塞住線程,如果在此期間其他線程釋放了鎖鸭限,則該線程可以獲得對互斥量的鎖蜕径,如果超時,則返回 false败京。 -
try_lock_until
同上面的解釋兜喻,只是傳入?yún)?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
同上面分析赡麦,遞歸的時間鎖朴皆,允許同一個線程對互斥量多次上鎖(即遞歸上鎖), 不再贅述泛粹。
(二)遂铡、Locks 模板類
lock_guard | Lock guard (class template ) | 模版類 |
unique_lock | Unique lock (class template ) | 模版類 |
-
lock_guard
定義: template <class Mutex> class lock_guard;
鎖保護(hù)是一個通過將互斥對象保持鎖定來管理互斥對象的對象。
在構(gòu)造上晶姊,互斥對象被調(diào)用線程鎖定扒接,并且在銷毀時,互斥鎖被解鎖们衙。它是最簡單的鎖钾怔,作為具有自動持續(xù)時間的對象特別有用,直到它的上下文結(jié)束蒙挑。這樣宗侦,它保證在拋出異常時,可以正確地鎖定互斥對象忆蚀。
注意矾利,lock_guard對象不以任何方式管理互斥對象的生命周期:互斥對象的持續(xù)時間至少要延長到鎖定它的lock_guard的銷毀為止姑裂。
模板參數(shù) Mutex 代表互斥量類型,例如 std::mutex 類型男旗,它應(yīng)該是一個基本的 BasicLockable 類型舶斧,標(biāo)準(zhǔn)庫中定義幾種基本的 BasicLockable 類型,分別 std::mutex, std::recursive_mutex, std::timed_mutexstd::recursive_timed_mutex 以及 std::unique_lock剑肯。 (注:BasicLockable 類型的對象只需滿足兩種操作捧毛,lock 和 unlock,另外還有 Lockable 類型让网,在 BasicLockable 類型的基礎(chǔ)上新增了 try_lock 操作呀忧,因此一個滿足 Lockable 的對象應(yīng)支持三種操作:lock,unlock 和 try_lock溃睹;最后還有一種 TimedLockable 對象而账,在 Lockable 類型的基礎(chǔ)上又新增了 try_lock_for 和 try_lock_until 兩種操作,因此一個滿足 TimedLockable 的對象應(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)鎖定初始化:對象管理m泞辐,并鎖定它(通過調(diào)用m.lock())。
(2)采用初始化:對象管理m竞滓,它是已經(jīng)當(dāng)前被構(gòu)造線程鎖定的互斥對象咐吼。
(3)復(fù)制構(gòu)造: 刪除(lock_guard對象不能被復(fù)制/移動)。
注:lock_guard的對象保持鎖定并管理m(通過調(diào)用它的成員解鎖)來解鎖它商佑,當(dāng)lock_guard的對象析構(gòu)的時候锯茄,mtx將會被解鎖。
示例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 對象以獨(dú)占所有權(quán)的方式(官方叫做unique ownership)管理 mutex 對象的上鎖和解鎖操作;獨(dú)占所有權(quán)抓半,就是沒有其他的 unique_lock 對象同時擁有某個 mutex 對象的所有權(quán)喂急。
unique_lock對象在析構(gòu)的時候一定保證互斥量為解鎖狀態(tài);因此它作為具有自動持續(xù)時間的對象特別有用笛求,因?yàn)樗WC在拋出異常時廊移,互斥對象被正確地解鎖。不過,注意unique_lock對象并不以任何方式管理互斥對象的生命周期:互斥對象的持續(xù)時間將延長至少直到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òu)造函數(shù):
(1) 默認(rèn)構(gòu)造函數(shù)
unique_lock 對象不管理任何 Mutex 對象m狡孔。
(2) locking 初始化
unique_lock 對象管理 Mutex 對象 m,并調(diào)用 m.lock() 對 Mutex 對象進(jìn)行上鎖新症,如果其他 unique_lock 對象已經(jīng)管理了m步氏,該線程將會被阻塞响禽。
(3) try-locking 初始化
unique_lock 對象管理 Mutex 對象 m徒爹,并調(diào)用 m.try_lock() 對 Mutex 對象進(jìn)行上鎖荚醒,但如果上鎖不成功,不會阻塞當(dāng)前線程隆嗅。
(4) deferred 初始化
unique_lock 對象管理 Mutex 對象 m并不鎖住m界阁。 m 是一個沒有被當(dāng)前線程鎖住的 Mutex 對象妒牙。
(5) adopting 初始化
unique_lock 對象管理 Mutex 對象 m踊沸, m 應(yīng)該是一個已經(jīng)被當(dāng)前線程鎖住的 Mutex 對象辛掠。(當(dāng)前unique_lock 對象擁有對鎖(lock)的所有權(quán))彻舰。
(6) locking 一段時間(duration)
新創(chuàng)建的 unique_lock 對象管理 Mutex 對象 m迄本,通過調(diào)用 m.try_lock_for(rel_time) 來鎖住 Mutex 對象一段時間(rel_time)帖汞。
(7) locking 直到某個時間點(diǎn)(time point)
新創(chuàng)建的 unique_lock 對象管理 Mutex 對象m纬朝,通過調(diào)用 m.try_lock_until(abs_time) 來在某個時間點(diǎn)(abs_time)之前鎖住 Mutex 對象个绍。
(8) 拷貝構(gòu)造 [被禁用]
unique_lock 對象不能被拷貝構(gòu)造技健。
(9) 移動(move)構(gòu)造
新創(chuàng)建的 unique_lock 對象獲得了由 x 所管理的 Mutex 對象的所有權(quán)(包括當(dāng)前 Mutex 的狀態(tài))写穴。調(diào)用 move 構(gòu)造之后, x 對象如同通過默認(rèn)構(gòu)造函數(shù)所創(chuàng)建的雌贱,就不再管理任何 Mutex 對象了啊送。
示例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)用被托管的互斥對象的成員鎖 |
try_lock | Lock mutex if not locked (public member function ) | 嘗試上鎖 |
try_lock_for | Try to lock mutex during time span (public member function ) | 嘗試在時間段上鎖 |
try_lock_until | Try to lock mutex until time point (public member function ) | 嘗試在時間點(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 ) | 交換兩個互斥對象 |
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
鎖定互斥對象,調(diào)用被托管的互斥對象的成員鎖。
對已經(jīng)被其他線程鎖定的互斥對象調(diào)用鎖欣孤,阻塞當(dāng)前線程(等待)馋没,直到鎖釋放。當(dāng)函數(shù)返回時降传,對象在互斥鎖上擁有一個鎖篷朵,如果調(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對象款票,并使用返回值設(shè)置擁有狀態(tài);如果擁有的狀態(tài)在調(diào)用前為真或者如果對象目前管理沒有互斥對象,函數(shù)拋出一個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);
在時間范圍span內(nèi)鎖定互斥鎖;調(diào)用try_lock_for管理時間的mutex對象,并使用返回值設(shè)置擁有狀態(tài);如果在調(diào)用之前擁有狀態(tài)已經(jīng)真或者如果對象目前管理沒有互斥對象,函數(shù)拋出一個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
同上面描述,傳入一個時間點(diǎn)而不是時間段翼悴。示例:同上改動缚够,不再述。
(5)std::unique_lock::unlock
調(diào)用unlock對托管的mutex對象進(jìn)行解鎖鹦赎,并將擁有的狀態(tài)設(shè)置為false谍椅;如果調(diào)用之前擁有狀態(tài)是錯誤,函數(shù)拋出一個system_error異常與operation_not_permitted錯誤條件。
示例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對象替換掉當(dāng)前對象的mutex古话,同時獲取x的狀態(tài)雏吭。替換掉的x將不再有mutex對象,如果對象在調(diào)用之前對其托管的mutex對象擁有一個鎖陪踩,那么它的解鎖成員在被替換之前就被調(diào)用了杖们。悉抵;unique_lock對象不能被復(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)容摘完,包括托管的互斥對象和它們當(dāng)前擁有的狀態(tài)姥饰。
(8) std::unique_lock::release
返回一個指向托管的互斥對象的指針,并釋放對它的所有權(quán);調(diào)用后unique_lock不再管理mutex對象(像默認(rèn)構(gòu)造一樣)孝治;注意列粪,該函數(shù)不會鎖定或釋放返回的互斥對象。
示例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對象擁有的一個鎖谈飒。unique_lock鎖定一個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
返回一個指向托管的mutex對象的指針瓤介。注意unique_lock不釋放互斥對象管理的所有權(quán)吕喘。如果它擁有一個互斥鎖,它仍然是負(fù)責(zé)釋放它在某一時刻(像當(dāng)unique_lock被銷毀的時候)。
示例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
此類型的對象用作call_once的參數(shù)氯质。
在不同的線程中使用相同的對象在不同的調(diào)用上調(diào)用call_once,如果同時調(diào)用祠斧,則會單個執(zhí)行闻察。
它是一個不可復(fù)制的、不可移動的琢锋、可構(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
這是一個空的類,用作adopt_lock的使用的類型吴超。
向unique_lock或lock_guard的構(gòu)造函數(shù)傳遞使用過的鎖钉嘹,使該對象不鎖定互斥對象,并假設(shè)它已經(jīng)被當(dāng)前線程鎖定鲸阻。
struct defer_lock_t {}; // 空類跋涣,只是作為adopt_lock類型constexpr adopt_lock_t adopt_lock {};
定義adopt_lock 值用作對unique_lock或lock_guard的構(gòu)造函數(shù)的可能參數(shù)。
使用adopt_lock構(gòu)造unique_lock對象不鎖定構(gòu)建中的互斥對象鸟悴,只是假設(shè)它已經(jīng)被當(dāng)前線程鎖定了陈辱;這個值是一個沒有狀態(tài)的編譯時常量,只是用來消除構(gòu)造函數(shù)簽名之間的歧義细诸。
defer_lock_t
這是一個空類沛贪,用作延遲鎖的類型。
將延遲鎖傳遞給unique_lock的構(gòu)造函數(shù),使它不會在構(gòu)造上自動鎖定互斥對象利赋,初始化對象為不擁有鎖嗅义。
struct defer_lock_t {};
constexpr defer_lock_t defer_lock {};
定義defer_lock用于unique_lock的構(gòu)造函數(shù)的可能的參數(shù)。使用延遲鎖構(gòu)造的unique_lock對象不將互斥對象自動鎖定在構(gòu)造上隐砸,并初始化它們不擁有鎖。同上面的一樣蝙眶,這個值是一個沒有狀態(tài)的編譯時常量季希,它只是用來消除構(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成員來鎖定互斥對象,代替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對象試圖通過調(diào)用其try_lock成員而不是鎖成員來鎖定互斥對象。
(四)收恢、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是一個模版函數(shù):
template <class Mutex1, class Mutex2, class... Mutexes>
int try_lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
使用try_lock成員函數(shù)(非阻塞)式的鎖定對象a,b...等武学。函數(shù)為每個參數(shù)調(diào)用try_lock成員函數(shù)(首先是a,然后是b伦意,最后是cde中的其他函數(shù))火窒,直到所有調(diào)用都是成功的,或者只要調(diào)用失敗(返回false或拋出異常)驮肉。如果函數(shù)結(jié)束是因?yàn)檎{(diào)用失敗熏矿,則對所有調(diào)用try_lock成功的對象調(diào)用解鎖,函數(shù)將返回鎖定失敗的對象的參數(shù)序號离钝。沒有對參數(shù)列表中的其余對象執(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同樣為一個模版函數(shù)
template <class Mutex1, class Mutex2, class... Mutexes>
void lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
鎖定所有的參數(shù)互斥對象,阻塞當(dāng)前調(diào)用線程卵渴;該函數(shù)使用一個未指定的調(diào)用序列來鎖定對象慧域,該序列調(diào)用其成員鎖、try_lock和解鎖浪读,以確保所有參數(shù)都被鎖定在返回(不產(chǎn)生任何死鎖)吊趾。
如果函數(shù)不能鎖定所有對象(例如,因?yàn)槠渲幸粋€內(nèi)部調(diào)用拋出異常)瑟啃,則函數(shù)首先解鎖所有成功鎖定的對象(如果有的話)论泛。
示例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,除非另一個線程已經(jīng)(或正在執(zhí)行)使用相同的flag調(diào)用執(zhí)行call_once蛹屿。如果已經(jīng)有一個線程使用相同flag調(diào)用call_once,會使得當(dāng)前變?yōu)楸粍訄?zhí)行屁奏,所謂被動執(zhí)行不執(zhí)行fn也不返回直到恢復(fù)執(zhí)行后返回。這這個時間點(diǎn)上所有的并發(fā)調(diào)用這個函數(shù)相同的flag都是同步的错负。
注意,一旦一個活躍調(diào)用返回了,所有當(dāng)前被動執(zhí)行和未來可能的調(diào)用call_once相同相同的flag也還不會成為積極執(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é)