C++中 鎖的使用 互斥鎖:std::mutex \std::lock_guard \std::unique_lock ,讀寫鎖使用shared_mutex ,條件變量使用std::condition_variable類


轉載:https://blog.csdn.net/faihung/article/details/88411839

  https://blog.csdn.net/XindaBlack/article/details/105915806

簡介:std::mutex:互斥量,C++11中與mutex相關的類(包括鎖類型)和函數都聲明在<mutex>頭文件中。(C++官網

讀寫鎖:后續補充

自旋鎖:后續補充

<mutex> 頭文件介紹

mutex系列類(四種):

  • std::mutex:最基本的mutex類
  • std::recursive_mutex:遞歸mutex類
  • std::timed_mutex:定時mutex類
  • std::recursive_timed_mutex:遞歸定時mutex類

lock類(兩種):

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

其他類型:

  • std::once_flag
  • std::adopt_lock_t
  • std::defer_lock_t
  • std::try_to_lock_t

函數:

  • std::try_lock:嘗試同時對多個互斥量上鎖
  • std::lock:可以同時對多個互斥量上鎖
  • std::call_once:如果多個線程需要同時調用某個函數,call_once可以保證多個線程對該函數只調用一次

std::mutex介紹

std::mutex是C++11中最基本的互斥量,std::mutex對象提供了獨占所有權的特性——既不支持遞歸地對std::mutex上鎖,而std::recursive_lock可以遞歸地對互斥量對象上鎖。

std::mutex的成員函數

  • 構造函數,std::mutex不允許拷貝構造函數,也不允許move拷貝,最初產生的mutex對象是處於unlocked狀態的。
  • lock(),調用線程將鎖住該互斥量。線程調用該函數會發生下面3中情況。(1)如果該互斥量當前沒有被鎖住,則調用線程將該互斥量鎖住,知道調用unlock之前,該線程會一直擁有該鎖。(2)如果當前互斥量被其他線程鎖住,則當前的調用線程被阻塞住。(3)如果當前互斥量被當前調用線程鎖住,則會產生死鎖。(第三條應該是遞歸鎖要解決的問題)
  • unlock(),解鎖,釋放對互斥量的所有權。
  • try_lock(),嘗試鎖住互斥量,如果互斥量被其他線程占有,則當前線程也不會阻塞。線程調用該函數也會出現下面3中情況。(1)如果當前互斥量沒有被其他線程占有,則該線程鎖住互斥量,直到該線程調用unlock釋放互斥量。(3)如果當前互斥量被當前調用線程鎖住,則會產生死鎖。

 

注意:在編譯的時候可能會報 underfined  reference to ‘pthread_create’錯誤,這個在編譯選項中加 -g -lpthread 既可。原因

具體編譯命令:

g++ -std=c++11 lock.cpp -g -lpthread

 

case 1:mutex 

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

volatile int counter(0);
mutex mtx;

void attempt_10k_increases() {
    for (int i = 0; i < 10000; ++i) {
        if (mtx.try_lock()) {
            ++counter;
            mtx.unlock();
        }
    }
}

int main(int argc, const char* argv[]) {
    thread threads[10];
    for (int i=0; i < 10; ++i) {
        threads[i] = thread(attempt_10k_increases);
    }

    for (auto& th : threads) {
        th.join();
    }

    cout << counter << " successful increases of the counter." << endl;

    return 0;
}

std::recursive_mutex介紹

std::recursive_mutex與std::mutex一樣,也是一種可以被上鎖的對象,但是和std::mutex不同的是,std::recursive_mutex允許同一個線程對互斥量多次上鎖(即遞歸上鎖),來獲取對互斥量對象的多層所有權,std::recursive_mutex釋放互斥量時需要調用與該鎖層次深度相同次數的unlock(),可理解為lock()次數 和 unlock()次數相同,除此之外,std::recursive_mutex的特性和std::mutex大致相同。

std::timed_mutex 介紹

std::timed_mutex 比 std::mutex多了兩個成員函數,try_lock_for(), try_lock_until()。

try_lock_for函數接受一個時間范圍,表示在這一段時間范圍之內線程如果沒有獲得鎖則被阻塞住(與std::mutex的try_lock不同, try_lock如果被調用時沒有獲得鎖則直接返回false),如果在此期間其他線程釋放了鎖,則該線程可以獲得互斥量的鎖,如果超時(即在指定時間內還是沒有獲得鎖),則返回false。

try_lock_until函數則接受一個時間點作為參數,在指定時間點未到來之前線程如果沒有獲得鎖則被阻塞住,如果在此期間其他線程釋放了鎖,則該線程獲得互斥量的鎖,如果超時(即在指定時間內還沒有獲得鎖),則返回false。

case 2 :timed_mutex

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

using namespace std;

timed_mutex mtx;

void  fireworks() {
    while (!mtx.try_lock_for(chrono::milliseconds(200))) {
        cout << "-" ;
    }

    this_thread::sleep_for(chrono::milliseconds(1000));
    cout << "*"  <<  endl;

    mtx.unlock();
}

int main() {
    thread threads[10];
    for (int i = 0; i <10;  ++i) {
        threads[i] = thread(fireworks);
    }

    for (auto &th : threads)
         th.join();

    return 0;    

 

std::recursive_timed_mutex 介紹

和std::recursive_mutex 與 std::mutex 的關系一樣,可以通過std::timed_mutex推到。

std::lock_guard介紹

與mutex RAI相關,方便線程對互斥量上鎖。

case 3:lock_guard

#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介紹

case 4 :unique_lock

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::unique_lock
 
std::mutex mtx;           // mutex for critical section
 
void print_block (int n, char c) {
    // critical section (exclusive access to std::cout signaled by lifetime of lck):
    std::unique_lock<std::mutex> lck (mtx);
    for (int i=0; i<n; ++i) {
        std::cout << c;
    }
    std::cout << '\n';
}
 
int main ()
{
    std::thread th1 (print_block,50,'*');
    std::thread th2 (print_block,50,'$');
 
    th1.join();
    th2.join();
 
    return 0;

 

unique_lock和lock_guard的區別:

簡單來說就是:unique_lock支持直接加鎖:unique_lock<mutex> lk(mtx);也支持lock和unlock函數。而lock_guard支持lock_guard<mutex> lk(mtx);

https://blog.csdn.net/qq_37233607/article/details/80159873


免責聲明!

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



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