欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++11互斥量的具體使用

 更新時間:2023年11月27日 11:39:17   作者:鏟灰  
互斥量是一種同步原語,是一種線程同步的手段,用來保護多線程同時訪問的共享數(shù)據(jù),本文主要介紹了C++11互斥量的具體使用,感興趣的可以了解一下

互斥量是一種同步原語,是一種線程同步的手段,用來保護多線程同時訪問的共享數(shù)據(jù)。

C++11中提供了如下4種語義的互斥量(mutex):

1、std::mutex:獨占的互斥量,不能遞歸使用。

2、std::mutex_mutex:帶超時的獨占互斥量,不能遞歸使用。

3、std::recursive_mutex:遞歸互斥量,不帶超時功能。

4、std::recursive_timed_mutex:帶超時的遞歸互斥量

獨占互斥量std::mutex

這些互斥量的基本接口很相似,一般用法是通過lock()方法來阻塞線程,直到獲得互斥量的所有權為止。在線程獲得互斥量并完成任務之后,就必須使用unlock()來解除對互斥量的占用,lock()和unlock()必須成對出現(xiàn)。try_lock()嘗試鎖定互斥量,如果成功則返回true,如果失敗則返回false,它是阻塞的。std::mutex的基本用法如下代碼。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

std::mutex g_lock;

void func()
{
    g_lock.lock();

    cout << "enter thread: " << std::this_thread::get_id() << endl;

    std::this_thread::sleep_for(std::chrono::seconds(1));

    cout << "leaving thread: " << std::this_thread::get_id() << endl;

    g_lock.unlock();
}

///g++ mutex.cpp -lpthread
int main()
{
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}

輸出結果如下:

enter thread: 140569127851776
leaving thread: 140569127851776
enter thread: 140568859412224
leaving thread: 140568859412224
enter thread: 140568590972672
leaving thread: 140568590972672

使用lock_guard可以簡化lock/unlock的寫法,同時也更安全,因為lock_guard在構造函數(shù)時會自動鎖定互斥量,而在退出作用域后進行析構時就會自動解鎖,從而保證了互斥量的正確操作,避免忘記unlock操作,因此,應盡量用lock_guard。lock_guard用到了RAII技術,這種技術在類的構造函數(shù)中分配資源,在析構函數(shù)中釋放資源,保證資源在出了作用域之后就釋放,上面的例子使用lock_guard后更簡潔,代碼如下:

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

std::mutex g_lock;

void func()
{
    std::lock_guard<std::mutex> locker(g_lock);///出了作用域之后自動解鎖

    cout << "enter thread: " << std::this_thread::get_id() << endl;

    std::this_thread::sleep_for(std::chrono::seconds(1));

    cout << "leaving thread: " << std::this_thread::get_id() << endl;

}

///g++ mutex.cpp -lpthread
int main()
{
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}

遞歸的獨占互斥量std::recursive_mutex

遞歸鎖允許同一個線程多次獲得該互斥鎖,可以用來解決同一個線程需要多次獲取互斥量死鎖的問題。在下面的代碼中,一個線程多次獲取同一個互斥量時會發(fā)生死鎖。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

struct Complex
{
public:
    Complex(){i = 20;}

    void mul(int x)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.lock();
        ///std::lock_guard<std::mutex> locker(g_mutex);
        i *= x;
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.unlock();
    }

    void div(int x)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.lock();
        ///std::lock_guard<std::mutex> locker(g_mutex);
        i /= x;
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.unlock();
    }

    void both(int x, int y)
    {
        ///std::lock_guard<std::mutex> locker(g_mutex);
        g_mutex.lock();
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        mul(x);
        div(y);
        g_mutex.unlock();
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
    }

private:
    int i;
    std::mutex g_mutex;
};


///g++ mutex.cpp -lpthread
int main()
{
    Complex complex;
    complex.both(2, 4);

    return 0;
}

這個例子運行起來就會發(fā)生死鎖,因為在調用both時獲取了互斥量,之后再調用mul又要獲取相同的互斥量,但是這個互斥量已經被當前線程獲取了,無法釋放,這時就會發(fā)生死鎖。要解決這個死鎖的問題,一個簡單的辦法就是用遞歸鎖:std::recursive_mutex,它允許同一個線程多次獲得互斥量。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

struct Complex
{
public:
    Complex(){i = 20;}

    void mul(int x)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.lock();
        ///std::lock_guard<std::recursive_mutex> locker(g_mutex);
        i *= x;
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.unlock();
    }

    void div(int x)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.lock();
        ///std::lock_guard<std::recursive_mutex> locker(g_mutex);
        i /= x;
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        g_mutex.unlock();
    }

    void both(int x, int y)
    {
        ///std::lock_guard<std::recursive_mutex> locker(g_mutex);
        g_mutex.lock();
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
        mul(x);
        div(y);
        g_mutex.unlock();
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
    }

private:
    int i;
    std::recursive_mutex g_mutex;
};

void func()
{
    Complex complex;
    complex.both(2, 4);
}

///g++ mutex.cpp -lpthread
int main()
{
    thread t1(func);

    t1.join();

    return 0;
}

需要注意的是盡量不要使用遞歸鎖,主要原因如下:

1、需要用到遞歸鎖定的多線程互斥處理往往本身就是可以簡化的,允許遞歸互斥很容易放縱復雜邏輯的產生,從而導致一些多線程同步引起的問題。

2、遞歸鎖比起非遞歸鎖,效率會低一些。

帶超時的互斥量std::timed_mutex

std::timed_mutex是超時的獨占鎖,主要用在獲取鎖時增加超時等待功能,因為有時不知道獲取鎖需要多久,為了不至于一直在等待獲取互斥量,就設置一個等待超時時間,在超時后還可以做其他事情。

std::timed_mutex比std::mutex多了兩個超時獲取鎖的接口:try_lock_for和try_lock_until,這兩個接口是用來設置獲取互斥量的超時時間,使用時可以用while循環(huán)取不斷地獲取互斥量。std::timed_mutex的基本用法如下所示。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

std::timed_mutex g_mutex;

void work()
{
    std::chrono::milliseconds timeout(1000);

    while(true)
    {
        if (g_mutex.try_lock_for(timeout))
        {
            cout << std::this_thread::get_id() << ": do work with the mutex" << endl;

            std::chrono::milliseconds sleepDuration(5000);

            std::this_thread::sleep_for(sleepDuration);

            g_mutex.unlock();

            std::this_thread::sleep_for(sleepDuration);
        }
        else
        {
            cout << std::this_thread::get_id() << ": do work without the mutex" << endl;

            std::chrono::milliseconds sleepDuration(2000);

            std::this_thread::sleep_for(sleepDuration);
        }
    }
}


///g++ mutex.cpp -lpthread
int main()
{
    std::thread t1(work);

    std::thread t2(work);

    t1.join();

    t2.join();

    return 0;
}

在上面的例子中,通過一個while循環(huán)不斷地去獲取超時鎖,如果超時還沒有獲取到鎖就會休眠,再繼續(xù)獲取超時鎖。

到此這篇關于C++11互斥量的具體使用的文章就介紹到這了,更多相關C++11互斥量內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Opencv實現(xiàn)聯(lián)合雙邊濾波

    Opencv實現(xiàn)聯(lián)合雙邊濾波

    這篇文章主要為大家詳細介紹了Opencv實現(xiàn)聯(lián)合雙邊濾波,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++中的類與對象深度解析

    C++中的類與對象深度解析

    這篇文章主要為大家詳細介紹了C++中的類與對象,使用數(shù)據(jù)庫,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 淺談C++高并發(fā)場景下讀多寫少的優(yōu)化方案

    淺談C++高并發(fā)場景下讀多寫少的優(yōu)化方案

    本文主要介紹了淺談C++高并發(fā)場景下讀多寫少的優(yōu)化方案,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++基于QWidget和QLabel實現(xiàn)圖片縮放,拉伸與拖拽

    C++基于QWidget和QLabel實現(xiàn)圖片縮放,拉伸與拖拽

    這篇文章主要為大家詳細介紹了C++如何基于QWidget和QLabel實現(xiàn)圖片縮放、拉伸與拖拽等功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-02-02
  • 基于C語言實現(xiàn)泛型編程詳解

    基于C語言實現(xiàn)泛型編程詳解

    對于C而言,想實現(xiàn)泛型編程并非易事,甚至可以說非常繁瑣,一大堆坑。最主要也沒有現(xiàn)成的輪子可用。本文就來詳細為大家講講C語言如何實現(xiàn)泛型編程詳解,需要的可以參考一下
    2022-07-07
  • MFC Frame-Splitter模型實例原理解析

    MFC Frame-Splitter模型實例原理解析

    這篇文章主要介紹了MFC Frame-Splitter模型實例原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • VScode中添加頭文件和源文件(C/C++)的方法

    VScode中添加頭文件和源文件(C/C++)的方法

    使用VSCode編譯C/C++時,會存在找不到頭文件的情況,下面這篇文章主要給大家介紹了關于VScode中添加頭文件和源文件(C/C++)的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • C++可以函數(shù)重載而C不可以的原因分析

    C++可以函數(shù)重載而C不可以的原因分析

    函數(shù)重載是指在同一個作用域內,可以定義多個函數(shù),它們具有相同的名稱但是參數(shù)列表不同,為什么C++可以函數(shù)重載而C不可以,接下來就有小編來給大家介紹一下C++可以函數(shù)重載而C不可以的原因,需要的朋友可以參考下
    2023-12-12
  • C語言模式實現(xiàn)C++繼承和多態(tài)的實例代碼

    C語言模式實現(xiàn)C++繼承和多態(tài)的實例代碼

    本篇文章主要介紹了C語言模式實現(xiàn)C++繼承和多態(tài)的實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • C語言中數(shù)據(jù)是如何存儲在內存中的

    C語言中數(shù)據(jù)是如何存儲在內存中的

    使用編程語言進行編程時,需要用到各種變量來存儲各種信息。變量保留的是它所存儲的值的內存位置。這意味著,當您創(chuàng)建一個變量時,就會在內存中保留一些空間。您可能需要存儲各種數(shù)據(jù)類型的信息,操作系統(tǒng)會根據(jù)變量的數(shù)據(jù)類型,來分配內存和決定在保留內存中存儲什么
    2022-04-04

最新評論