boost--線程同步


 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;
}
View Code

  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;
}
View Code

  使用實例:以下定義了一個支持原子前++的計數器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;
}
View Code

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); //寫鎖定
        //......
    }
View Code

 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;
}
View Code

 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; }
View Code

  創建線程的時候需要注意三點:

  ①、如果使用函數對象作為thread的參數的話,直接傳入臨時對象會出錯,可以定義一個對象傳入或者使用lambda表達式:

class CTask { public: void operator()() { int a = 0; } }; //std::thread th1(CTask()); //直接傳入臨時對象會出錯
CTask task; std::thread th1(task); th1.join();
View Code

  ②、傳遞給線程函數的參數是先保存在於一個中轉站中,當函數執行的時候再傳給函數的形參,而這個時候傳遞的參數指向的值很有可能已經失效,所以,對於線程函數傳遞的參數應該與形參類型相同,而不是再進行轉換。

  ③、如果線程函數的參數是引用的話傳入時還需要結合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();
View Code

  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
}
View Code

  unique_lock可以配合條件變量來使用,而lock_guard不能,因為lock_guard沒有加鎖和解鎖的接口方法。另外,unique_lock和lock_guard都不能復制,unique_lock可以移動,lock_guard不能移動。c++11中的條件變量condition_variable與boost的使用類似,其接口方法有wait()、notify_one()等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM