C++11 併發指南三(Lock 詳解)

在 《C++11 併發指南三(std::mutex 詳解)》一文中咱們主要介紹了 C++11 標準中的互斥量(Mutex),並簡單介紹了一下兩種鎖類型。本節將詳細介紹一下 C++11 標準的鎖類型。html

C++11 標準爲咱們提供了兩種基本的鎖類型,分別以下:ios

  • std::lock_guard,與 Mutex RAII 相關,方便線程對互斥量上鎖。
  • std::unique_lock,與 Mutex RAII 相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。

另外還提供了幾個與鎖類型相關的 Tag 類,分別以下:程序員

  • std::adopt_lock_t,一個空的標記類,定義以下:
struct adopt_lock_t {};

 該類型的常量對象adopt_lock(adopt_lock 是一個常量對象,定義以下:編程

constexpr adopt_lock_t adopt_lock {};,// constexpr 是 C++11 中的新關鍵字)

一般做爲參數傳入給 unique_lock 或 lock_guard 的構造函數。 安全

  • std::defer_lock_t,一個空的標記類,定義以下:
struct defer_lock_t {};

 該類型的常量對象 defer_lockdefer_lock 是一個常量對象,定義以下:多線程

constexpr defer_lock_t defer_lock {};,// constexpr 是 C++11 中的新關鍵字)

一般做爲參數傳入給 unique_lock 或 lock_guard 的構造函數。 併發

  • std::try_to_lock_t,一個空的標記類,定義以下:
struct try_to_lock_t {};

 該類型的常量對象 try_to_locktry_to_lock 是一個常量對象,定義以下:函數

constexpr try_to_lock_t try_to_lock {};,// constexpr 是 C++11 中的新關鍵字)

一般做爲參數傳入給 unique_lock 或 lock_guard 的構造函數。後面咱們會詳細介紹以上三種 Tag 類型在配合 lock_gurad 與 unique_lock 使用時的區別。this

std::lock_guard 介紹

std::lock_gurad 是 C++11 中定義的模板類。定義以下:spa

template <class Mutex> class lock_guard;

lock_guard 對象一般用於管理某個鎖(Lock)對象,所以與 Mutex RAII 相關,方便線程對互斥量上鎖,即在某個 lock_guard 對象的聲明週期內,它所管理的鎖對象會一直保持上鎖狀態;而 lock_guard 的生命週期結束以後,它所管理的鎖對象會被解鎖(注:相似 shared_ptr 等智能指針管理動態分配的內存資源 )。

模板參數 Mutex 表明互斥量類型,例如 std::mutex 類型,它應該是一個基本的 BasicLockable 類型,標準庫中定義幾種基本的 BasicLockable 類型,分別 std::mutex, std::recursive_mutex, std::timed_mutex,std::recursive_timed_mutex (以上四種類型均已在上一篇博客中介紹)以及 std::unique_lock(本文後續會介紹 std::unique_lock)。(注:BasicLockable 類型的對象只需知足兩種操做,lock 和 unlock,另外還有 Lockable 類型,在 BasicLockable 類型的基礎上新增了 try_lock 操做,所以一個知足 Lockable 的對象應支持三種操做:lock,unlock 和 try_lock;最後還有一種 TimedLockable 對象,在 Lockable 類型的基礎上又新增了 try_lock_for 和 try_lock_until 兩種操做,所以一個知足 TimedLockable 的對象應支持五種操做:lock, unlock, try_lock, try_lock_for, try_lock_until)。

在 lock_guard 對象構造時,傳入的 Mutex 對象(即它所管理的 Mutex 對象)會被當前線程鎖住。在lock_guard 對象被析構時,它所管理的 Mutex 對象會自動解鎖,因爲不須要程序員手動調用 lock 和 unlock 對 Mutex 進行上鎖和解鎖操做,所以這也是最簡單安全的上鎖和解鎖方式,尤爲是在程序拋出異常後先前已被上鎖的 Mutex 對象能夠正確進行解鎖操做,極大地簡化了程序員編寫與 Mutex 相關的異常處理代碼。

值得注意的是,lock_guard 對象並不負責管理 Mutex 對象的生命週期,lock_guard 對象只是簡化了 Mutex 對象的上鎖和解鎖操做,方便線程對互斥量上鎖,即在某個 lock_guard 對象的聲明週期內,它所管理的鎖對象會一直保持上鎖狀態;而 lock_guard 的生命週期結束以後,它所管理的鎖對象會被解鎖。

std::lock_guard 構造函數

lock_guard 構造函數以下表所示:

locking (1)
explicit lock_guard (mutex_type& m);
adopting (2)
lock_guard (mutex_type& m, adopt_lock_t tag);
copy [deleted](3)
lock_guard (const lock_guard&) = delete;
  1. locking 初始化
    • lock_guard 對象管理 Mutex 對象 m,並在構造時對 m 進行上鎖(調用 m.lock())。
  2. adopting初始化
    • lock_guard 對象管理 Mutex 對象 m,與 locking 初始化(1) 不一樣的是, Mutex 對象 m 已被當前線程鎖住。
  3. 拷貝構造
    • lock_guard 對象的拷貝構造和移動構造(move construction)均被禁用,所以 lock_guard 對象不可被拷貝構造或移動構造。

咱們來看一個簡單的例子(參考):

#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;
}

在 print_thread_id 中,咱們首先對 mtx 進行上鎖操做(mtx.lock();),而後用 mtx 對象構造一個 lock_guard 對象(std::lock_guard<std::mutex> lck(mtx, std::adopt_lock);),注意此時 Tag 參數爲 std::adopt_lock,代表當前線程已經得到了鎖,此後 mtx 對象的解鎖操做交由 lock_guard 對象 lck 來管理,在 lck 的生命週期結束以後,mtx 對象會自動解鎖。

lock_guard 最大的特色就是安全易於使用,請看下面例子(參考),在異常拋出的時候經過 lock_guard 對象管理的 Mutex 能夠獲得正確地解鎖。

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::lock_guard
#include <stdexcept>      // std::logic_error

std::mutex mtx;

void print_even (int x) {
  if (x%2==0) std::cout << x << " is even\n";
  else throw (std::logic_error("not even"));
}

void print_thread_id (int id) {
  try {
    // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
    std::lock_guard<std::mutex> lck (mtx);
    print_even(id);
  }
  catch (std::logic_error&) {
    std::cout << "[exception caught]\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;
}

std::unique_lock 介紹

可是 lock_guard 最大的缺點也是簡單,沒有給程序員提供足夠的靈活度,所以,C++11 標準中定義了另一個與 Mutex RAII 相關類 unique_lock,該類與 lock_guard 類類似,也很方便線程對互斥量上鎖,但它提供了更好的上鎖和解鎖控制。

顧名思義,unique_lock 對象以獨佔全部權的方式( unique owership)管理 mutex 對象的上鎖和解鎖操做,所謂獨佔全部權,就是沒有其餘的 unique_lock 對象同時擁有某個 mutex 對象的全部權。

在構造(或移動(move)賦值)時,unique_lock 對象須要傳遞一個 Mutex 對象做爲它的參數,新建立的 unique_lock 對象負責傳入的 Mutex 對象的上鎖和解鎖操做。

std::unique_lock 對象也能保證在其自身析構時它所管理的 Mutex 對象可以被正確地解鎖(即便沒有顯式地調用 unlock 函數)。所以,和 lock_guard 同樣,這也是一種簡單而又安全的上鎖和解鎖方式,尤爲是在程序拋出異常後先前已被上鎖的 Mutex 對象能夠正確進行解鎖操做,極大地簡化了程序員編寫與 Mutex 相關的異常處理代碼。

值得注意的是,unique_lock 對象一樣也不負責管理 Mutex 對象的生命週期,unique_lock 對象只是簡化了 Mutex 對象的上鎖和解鎖操做,方便線程對互斥量上鎖,即在某個 unique_lock 對象的聲明週期內,它所管理的鎖對象會一直保持上鎖狀態;而 unique_lock 的生命週期結束以後,它所管理的鎖對象會被解鎖,這一點和 lock_guard 相似,但 unique_lock 給程序員提供了更多的自由,我會在下面的內容中給你們介紹 unique_lock 的用法。

另外,與 lock_guard 同樣,模板參數 Mutex 表明互斥量類型,例如 std::mutex 類型,它應該是一個基本的 BasicLockable 類型,標準庫中定義幾種基本的 BasicLockable 類型,分別 std::mutex, std::recursive_mutex, std::timed_mutex,std::recursive_timed_mutex (以上四種類型均已在上一篇博客中介紹)以及 std::unique_lock(本文後續會介紹 std::unique_lock)。(注:BasicLockable 類型的對象只需知足兩種操做,lock 和 unlock,另外還有 Lockable 類型,在 BasicLockable 類型的基礎上新增了 try_lock 操做,所以一個知足 Lockable 的對象應支持三種操做:lock,unlock 和 try_lock;最後還有一種 TimedLockable 對象,在 Lockable 類型的基礎上又新增了 try_lock_for 和 try_lock_until 兩種操做,所以一個知足 TimedLockable 的對象應支持五種操做:lock, unlock, try_lock, try_lock_for, try_lock_until)。

std::unique_lock 構造函數

std::unique_lock 的構造函數的數目相對來講比 std::lock_guard 多,其中一方面也是由於 std::unique_lock 更加靈活,從而在構造 std::unique_lock 對象時能夠接受額外的參數。總地來講,std::unique_lock 構造函數以下:

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);

下面咱們來分別介紹以上各個構造函數:

(1) 默認構造函數
新建立的 unique_lock 對象無論理任何 Mutex 對象。
(2) locking 初始化
新建立的 unique_lock 對象管理 Mutex 對象 m,並嘗試調用 m.lock() 對 Mutex 對象進行上鎖,若是此時另外某個 unique_lock 對象已經管理了該 Mutex 對象 m,則當前線程將會被阻塞。
(3) try-locking 初始化
新建立的 unique_lock 對象管理 Mutex 對象 m,並嘗試調用 m.try_lock() 對 Mutex 對象進行上鎖,但若是上鎖不成功,並不會阻塞當前線程。
(4) deferred 初始化
新建立的 unique_lock 對象管理 Mutex 對象 m,可是在初始化的時候並不鎖住 Mutex 對象。 m 應該是一個沒有當前線程鎖住的 Mutex 對象。
(5) adopting 初始化
新建立的 unique_lock 對象管理 Mutex 對象 m, m 應該是一個已經被當前線程鎖住的 Mutex 對象。(而且當前新建立的 unique_lock 對象擁有對鎖(Lock)的全部權)。
(6) locking 一段時間(duration)
新建立的 unique_lock 對象管理 Mutex 對象 m,並試圖經過調用 m.try_lock_for(rel_time) 來鎖住 Mutex 對象一段時間(rel_time)。
(7) locking 直到某個時間點(time point)
新建立的 unique_lock 對象管理 Mutex 對象m,並試圖經過調用 m.try_lock_until(abs_time) 來在某個時間點(abs_time)以前鎖住 Mutex 對象。
(8) 拷貝構造 [被禁用]
unique_lock 對象不能被拷貝構造。
(9) 移動(move)構造
新建立的 unique_lock 對象得到了由 x 所管理的 Mutex 對象的全部權(包括當前 Mutex 的狀態)。調用 move 構造以後, x 對象如同經過默認構造函數所建立的,就再也不管理任何 Mutex 對象了。

綜上所述,由 (2) 和 (5) 建立的 unique_lock 對象一般擁有 Mutex 對象的鎖。而經過 (1) 和 (4) 建立的則不會擁有鎖。經過 (3),(6) 和 (7) 建立的 unique_lock 對象,則在 lock 成功時得到鎖。

關於unique_lock 的構造函數,請看下面例子(參考):

#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;
}

std::unique_lock 移動(move assign)賦值操做

std::unique_lock 支持移動賦值(move assignment),可是普通的賦值被禁用了,

move (1)
unique_lock& operator= (unique_lock&& x) noexcept;
copy [deleted] (2)
unique_lock& operator= (const unique_lock&) = delete;

移動賦值(move assignment)以後,由 x 所管理的 Mutex 對象及其狀態將會被新的 std::unique_lock 對象取代。

若是被賦值的對象以前已經得到了它所管理的 Mutex 對象的鎖,則在移動賦值(move assignment)以前會調用 unlock 函數釋放它所佔有的鎖。

調用移動賦值(move assignment)以後, x 對象如同經過默認構造函數所建立的,也就再也不管理任何 Mutex 對象了。請看下面例子(參考):

#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;
}

std::unique_lock 主要成員函數

本節咱們來看看 std::unique_lock 的主要成員函數。因爲 std::unique_lock 比 std::lock_guard 操做靈活,所以它提供了更多成員函數。具體分類以下:

  1. 上鎖/解鎖操做:lock,try_lock,try_lock_for,try_lock_until unlock
  2. 修改操做:移動賦值(move assignment)(前面已經介紹過了),交換(swap)(與另外一個 std::unique_lock 對象交換它們所管理的 Mutex 對象的全部權),釋放(release)(返回指向它所管理的 Mutex 對象的指針,並釋放全部權)
  3. 獲取屬性操做:owns_lock(返回當前 std::unique_lock 對象是否得到了鎖)、operator bool()(與 owns_lock 功能相同,返回當前 std::unique_lock 對象是否得到了鎖)、mutex(返回當前 std::unique_lock 對象所管理的 Mutex 對象的指針)。

std::unique_lock::lock請看下面例子(參考):

上鎖操做,調用它所管理的 Mutex 對象的 lock 函數。若是在調用  Mutex 對象的 lock 函數時該 Mutex 對象已被另外一線程鎖住,則當前線程會被阻塞,直到它得到了鎖。

該函數返回時,當前的 unique_lock 對象便擁有了它所管理的 Mutex 對象的鎖。若是上鎖操做失敗,則拋出 system_error 異常。

// 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;
}

std::unique_lock::try_lock

上鎖操做,調用它所管理的 Mutex 對象的 try_lock 函數,若是上鎖成功,則返回 true,不然返回 false。

請看下面例子(參考):

#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();

  return 0;
}

std::unique_lock::try_lock_for

上鎖操做,調用它所管理的 Mutex 對象的 try_lock_for 函數,若是上鎖成功,則返回 true,不然返回 false。

請看下面例子(參考):

#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;
}

std::unique_lock::try_lock_until

上鎖操做,調用它所管理的 Mutex 對象的 try_lock_for 函數,若是上鎖成功,則返回 true,不然返回 false。

請看下面例子(參考):

#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;
}

std::unique_lock::unlock

解鎖操做,調用它所管理的 Mutex 對象的 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;
}

std::unique_lock::release

返回指向它所管理的 Mutex 對象的指針,並釋放全部權。

請看下面例子(參考):

#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;
}

std::unique_lock::owns_lock

返回當前 std::unique_lock 對象是否得到了鎖。

請看下面例子(參考):

#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();

  return 0;
}

std::unique_lock::operator bool()

與 owns_lock 功能相同,返回當前 std::unique_lock 對象是否得到了鎖。

請看下面例子(參考):

#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)
    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();

  return 0;
}

std::unique_lock::mutex

返回當前 std::unique_lock 對象所管理的 Mutex 對象的指針。

請看下面例子(參考):

#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;
}

好了,本文先介紹到這裏,咱們基本上介紹完了 C++11 多線程編程中兩種最基本的鎖類型,後面我會繼續更新有關 C++11 併發編程的博客,但願感興趣的同窗繼續關注 ;-)

相關文章
相關標籤/搜索