【C++多線程】共享數據保護


  保護共享數據的最基本的方式,是使用C++標准庫提供的互斥量(頭文件<mutex>)。當訪問共享數據前,使用互斥量將相關數據鎖住,再當訪問結束后,再將數據解鎖。線程庫需要保證,當一個線程使用特定互斥量鎖住共享數據時,其他的線程想要訪問鎖住的數據,都必須等到之前那個線程對數據進行解鎖后,才能進行訪問。這就保證了所有線程能看到共享數據,而不破壞不變量。

  C++中通過實例化 std::mutex 創建互斥量,通過調用成員函數lock()進行上鎖,unlock()進行解鎖。

 1 #include <iostream>
 2 #include <thread>
 3 #include <mutex>
 4 #include <list>
 5 
 6 using namespace std;
 7 
 8 class A {
 9 public:
10     void input()
11     {
12         for (int i = 0; i < 1000; i++)
13         {
14             my_mutex.lock();
15             cout << "加入數據:" << i << endl;
16             ilst.push_back(i);
17             my_mutex.unlock();
18         }
19 
20     }
21 
22     void output()
23     {
24         for (int i = 0; i < 1000; i++)
25         {
26             my_mutex.lock();
27             if (!ilst.empty())
28             {
29                 cout << "讀讀讀讀出數據:" << ilst.front() << endl;
30                 ilst.pop_front();
31                 my_mutex.unlock();
32             }
33             else
34                 my_mutex.unlock();
35         }
36     }
37 
38 private:
39     list<int> ilst;
40     mutex my_mutex;
41 };
42 
43 int  main()
44 {
45     A a;
46     thread t1(&A::input, &a); //注意此處需要傳入的是對象地址,否則數據沒辦法共享
47     thread t2(&A::output, &a);
48     t1.join();
49     t2.join();
50     return 0;
51 }

 

  C++標准庫還為互斥量提供了一個RAII語法的模板類 std::lack_guard<T> ,其會在構造的時候提供已鎖的互斥量,並在析構的時候進行解鎖,從而保證了一個已鎖的互斥量總是會被正確的解鎖。

 1 #include <iostream>
 2 #include <thread>
 3 #include <mutex>
 4 #include <list>
 5 
 6 using namespace std;
 7 
 8 class A {
 9 public:
10     void input()
11     {
12         for (int i = 0; i < 1000; i++)
13         {
14             lock_guard<mutex> guard(my_mutex);
15             /*my_mutex.lock();*/
16             cout << "加入數據:" << i << endl;
17             ilst.push_back(i);
18            /* my_mutex.unlock();*/
19         }
20 
21     }
22 
23     void output()
24     {
25         for (int i = 0; i < 1000; i++)
26         {
27             lock_guard<mutex> guard(my_mutex);
28             /*my_mutex.lock();*/
29             if (!ilst.empty())
30             {
31                 cout << "讀讀讀讀出數據:" << ilst.front() << endl;
32                 ilst.pop_front();
33                 /*my_mutex.unlock();*/
34             }
35             /*else
36                 my_mutex.unlock();*/
37         }
38     }
39 
40 private:
41     list<int> ilst;
42     mutex my_mutex;
43 };
44 
45 int  main()
46 {
47     A a;
48     thread t1(&A::input, &a); //注意此處需要傳入的是對象地址,否則數據沒辦法共享
49     thread t2(&A::output, &a);
50     t1.join();
51     t2.join();
52     return 0;
53 }

 

  但互斥量自身也有問題。

  當其中一個成員函數返回的是保護數據的指針或引用時,會破壞對數據的保護。具有訪問能力的指針或引用可以訪問(並可能修改)被保護的數據,而不會被互斥鎖限制。所以切勿將受保護數據的指針或引用傳遞到互斥鎖作用域之外,無論是函數返回值,還是存儲在外部可見內存,亦或是以參數的形式傳遞到用戶提供的函數中去。

  另外還會造成死鎖,或是對數據保護的太多(或太少)的問題

 


免責聲明!

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



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