1、互斥鎖(互斥量)
mutex是獨占式的互斥鎖。timed_mutex增加了超時功能。
成員函數:lock()用於鎖定,try_lock()為非阻塞版本的鎖定,unlock()用於解鎖。timed_lock()只屬於timed_mutex,它可以等待一定的時間,等待的時間可以是一個時間段,也可以是指定的時間。
使用方法:使用mutex必須配合try-catch塊以保證解鎖互斥量,eg:

#include "boost\thread.hpp" int main() { boost::mutex mu; try { mu.lock(); cout << "Need to be protected" << endl; //io流是個共享資源,多線程內使用的話需要同步 mu.unlock(); } catch (...) { mu.unlock(); } return 0; }
mutex還提供了一系列的RAII型的互斥鎖,用於取消麻煩的try-catch塊,它會在構造的時候鎖定互斥量,析構時自動解鎖,eg:

#include "boost\thread.hpp" int main() { boost::mutex mu; boost::mutex::scoped_lock lock(mu); cout << "Need to be protected" << endl; //io流是個共享資源,多線程內使用的話需要同步 return 0; }
使用實例:以下定義了一個支持原子前++的計數器atom_increase:

#include "boost\thread.hpp" template<typename T> class atom_increase { public: atom_increase(T x = 0): n(x){} //轉換構造函數,實現T類型到atom_increase類型的隱式轉換 T operator++() //重載前++運算符 { boost::mutex::scoped_lock lock(mu); return ++n; } operator T() { return n; } //類型轉換函數,實現atom_increase類型到T類型的隱式轉換 private: T n; boost::mutex mu; }; int main() { atom_increase<int> n = 0; //隱式轉換:int -> atom_increase ++n; //原子前++ int i = 5 + n; //隱式轉換:atom_increase ->int return 0; }
2、遞歸鎖
recursive_mutex是遞歸鎖,可以多次鎖定,相應的也要多次解鎖。recursive_timed_mutex增加了超時功能。遞歸鎖的使用接口跟互斥鎖基本相同。
3、讀寫鎖
shared_mutex是讀寫鎖,提供了multiple-reader / single-writer功能。讀取鎖定時我們使用shared_lock<shared_mutex>對象,寫入鎖定時我們使用unique_lock<shared_mutex>對象:

boost::shared_mutex rw_mu; //read thread { boost::shared_lock<boost::shared_mutex> sl(rw_mu); //讀鎖定 //...... } //write thread { boost::unique_lock<boost::shared_mutex> ul(rw_mu); //寫鎖定 //...... }
4、條件變量
condition_variable_any是條件變量,它用來在一個線程中等待某個事件的發生(滿足某個條件),另一個線程會使條件成立。條件變量需要與一個互斥量配合使用。condition_variable_any::wait()用來等待條件滿足,wait_for()用來等待條件滿足直到超時,wait_until()用來等待條件滿足直到指定的時間, condition_variable_any::notify_one() / notify_all()用來在條件滿足的時候通知條件變量。
boost中的條件變量的使用方法與posix或windows下條件變量使用方法基本一致:

#include "boost\thread.hpp" boost::condition_variable_any g_cd; boost::mutex g_mu; bool g_bConditionFlag = false; void Thread1Proc() { boost::mutex::scoped_lock lock(g_mu); while (!g_bConditionFlag) { boost::this_thread::sleep(boost::posix_time::seconds(1)); g_cd.wait(g_mu); } printf("thread1 exit\n"); } int main() { boost::thread t(Thread1Proc); t.detach(); boost::this_thread::sleep(boost::posix_time::milliseconds(100)); g_mu.lock(); g_bConditionFlag = true; g_cd.notify_one(); g_mu.unlock(); printf("here\n"); getchar(); return 0; }
5、barrier
barrier稱為護欄,它可以用來設置線程執行到barrier時必須等待,直到所有線程都達到這個點時才繼續執行。
6、C++11中的線程操作
c++11也提供了創建線程和線程同步的方法,c++11里的mutex,與boost里的mutex用法類似:

#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();
std::lock(foo, bar); std::cout << "task a\n"; foo.unlock(); bar.unlock(); } void task_b() { // bar.lock(); // foo.lock();
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.detach(); // th2.detach();
th1.join(); th2.join(); return 0; }
創建線程的時候需要注意三點:
①、如果使用函數對象作為thread的參數的話,直接傳入臨時對象會出錯,可以定義一個對象傳入或者使用lambda表達式:

class CTask { public: void operator()() { int a = 0; } }; //std::thread th1(CTask()); //直接傳入臨時對象會出錯
CTask task; std::thread th1(task); th1.join();
②、傳遞給線程函數的參數是先保存在於一個中轉站中,當函數執行的時候再傳給函數的形參,而這個時候傳遞的參數指向的值很有可能已經失效,所以,對於線程函數傳遞的參數應該與形參類型相同,而不是再進行轉換。
③、如果線程函數的參數是引用的話傳入時還需要結合ref來使用。

void task(int& a, string str) { } int iNum = 0; char* pStr = new char[100]; strcpy(pStr, "test"); //std::thread th(task, 5, std::ref(iNum), pStr); //不應該直接傳入pStr
std::thread th(task, std::ref(iNum), string(pStr)); //應該傳入對應類型
delete[] pStr; th.join();
c++中的lock_guard、unique_lock也是RAII型的互斥鎖,類似boost的scoped_lock,使用示例:
std::lock_guard<std::mutex> _lock(m_mutex); g_num++;
unique_lock在lock_guard的基礎上增加了加鎖和解鎖的接口方法,對比下面的fun1和fun2,二者效果相同,通過代碼可以看出二者區別:

std::mutex g_mu; void fun1() { { std::lock_guard<std::mutex> guard(g_mu); //do something 1
} //do something 2
{ std::lock_guard<std::mutex> guard(g_mu); // do something 3
} } void fun2() { std::unique_lock<std::mutex> guard(g_mu); //do something 1
guard.unlock(); //do something 2
guard.lock(); // do something 3
}
unique_lock可以配合條件變量來使用,而lock_guard不能,因為lock_guard沒有加鎖和解鎖的接口方法。另外,unique_lock和lock_guard都不能復制,unique_lock可以移動,lock_guard不能移動。c++11中的條件變量condition_variable與boost的使用類似,其接口方法有wait()、notify_one()等。