1. 程式人生 > >C++多執行緒-第二篇-Mutex(互斥量)

C++多執行緒-第二篇-Mutex(互斥量)

//Boost#include<boost/thread/thread.hpp>#define BOOST_THREAD_VERSION 4 //使用最新版本,含有1,2,3但只是為了相容之前程式。

Thread庫豐富強大的擴充套件功能但不在Thread中的未看。

//C++11

#include <mutex>

using namspace std; 

Mutex(互斥量)

1.Mutex類

基本作用: 互斥佔有一個變數,一段時間內僅一個執行緒可以訪問。

即該類可以限制對某物的訪問,只有先獲得許可才可訪問某物,否則一般可設為阻塞等待。

互斥量*6

mull_mutex

無任何鎖定功能的“互斥量”,空物件模式是用。

mutex

獨佔式互斥量,最簡單但最常用

timed_mutex

獨佔式互斥量,一段時間內試圖鎖定,若超時則返回false

recursive_mutex

遞迴式互斥量,可以多次鎖定,相應的也要多次解鎖

Recursive_timed_mutex

遞迴式互斥量,同樣增加一段時間內試圖鎖定,若超時則返回false

Shared_mutex

多讀者,單寫者的共享互斥量(讀寫鎖)

一般成員函式:

Class Mutex

{

Public:

Void lock(); //鎖定,否則阻塞

Void unlock(); // 解鎖

Bool try_lock(); //嘗試鎖定,但不會阻塞

Bool try_lock_for(const duration &rel_time); //timed_ 特有,阻塞一段時間後嘗試鎖定

Bool try_lock_until(const time_point &t);// timed_ 特有,阻塞一段時間後嘗試鎖定

others...

};

Code:

  1. mutex mutex_thread_1;
  2. try
  3. {
  4. mutex_thread_1.lock();
  5. cout << "Do Something" << endl;
  6. mutex_thread_1.unlock();
  7. }
  8. catch (std::exception e)
  9. {
  10. //cout << << endl;;
  11. mutex_thread_1.unlock();
  12. }
  13. timed_mutex t_mutex_1;
  14. auto flag = t_mutex_1.try_lock_for(boost::chrono::milliseconds(100));
  15. if (flag)
  16. {
  17. cout << "訪問共享" << endl;
  18. t_mutex_1.unlock();
  19. }
  20. else
  21. {
  22. cout << "未獲得鎖,進行其他操作" << endl;
  23. }

2.Lock_guard()-- Mute的優秀輔助

作用:此類輔助鎖定互斥量,構造時鎖定,析構時解鎖,避免遺忘解鎖,也就是說在其作用域內他會一直鎖定要求的變數。

類似智慧指標?

附加擴充套件:with_lock_guard()藉助lock_guard()在函式中互斥使用某鎖定資源,(封裝函式用?)

  1. mutex mu;
  2. lock_guard<mutex> g(mu);//作用域內自動智慧加鎖/解鎖
  3. cout << "Do something" << endl;
  4. timed_mutex t_mu;
  5. if (mu.try_lock_for(boost::chrono::microseconds(100)))
  6. {
  7. lock_guard<timed_mutex> g(t_mu,adopt_lock);//不會再次加鎖
  8. cout << "Do something" << endl;
  9. }
[cpp] view plain copy print?
  1. <code class="language-cpp">#include <boost/thread/with_lock_guard.hpp></code>  
#include <boost/thread/with_lock_guard.hpp>
  1. #bind()封裝用
  2. //with_lock_guard
  3. mutex fmu;
  4. string name = "ZGJ";
  5. int rul = with_lock_guard(fmu, bind(Alloa,argv1,argv2...));//新增引數需謹慎,為Boost中引數型別,Alloa為函式,argv為其引數
  6. cout << rul << endl;
  7. With_lock_guard(lockable& m, Function && fun, Args &&...args) 類似於
  8. {
  9. Lock_guard<lockable> g(m);
  10. Return func(argc...)
  11. }

3. unique_lock()--升級lock_guard()

該類有很豐富的選項,但不可複製。例如:鎖定選項---佔有但不鎖定

如建構函式有

 unique_lock(Lockable & mu) ;//鎖定

 unique_lock(Lockable & mu,boost::adopt_lock_t);//不鎖定,但會解鎖

 unique_lock(Lockable & mu,boost::defer_lock_t);//不鎖定互斥量

 unique_lock(Lockable & mu,boost::try_to_lock_t);//嘗試鎖定互斥量

 unique_lock(Lockable & mu,const time_point &t);//超時鎖定

make_unique_lock(Lockable &mu,option);

//基於unique_lock(),利用函式過載幫助我們不用輸入互斥量型別,其實就是類似於

templat<class T_>

unique_lock<lockable> my_make_unique_lock(lockable& mu, T_ my_x)

{return unique_lock<lockable>(mux,my_x);

}

Code:

  1. #include<boost\thread\lock_factories.hpp>
  2. mutex m_un_lock;
  1. {//此類大括號活用作用域,供make_unique_lock析構使用。
  2. auto g = make_unique_lock(m_un_lock);//工廠函式鎖定互斥量
  3. assert(g.owns_lock());//斷言 -- 已經鎖定
  4. cout << "Do something" << endl;
  5. }
  6. {
  7. auto g = make_unique_lock(m_un_lock, defer_lock);//暫不鎖定互斥量
  8. assert(!g);// 斷言 -- 沒有鎖定
  9. assert(g.try_lock());//嘗試鎖定
  10. assert(g);//斷言 -- 已經鎖定
  11. cout << "Do something" << endl;
  12. }
  13. timed_mutex t_mu_un;
  14. {
  15. auto g = unique_lock<timed_mutex>(t_mu_un, boost::chrono::milliseconds(100)); //限時100MS嘗試鎖定
  16. if (g)
  17. {
  18. cout << "Lock timed mutex" << endl;
  19. }
  20. }
  21. auto g = make_unique_locks(t_mu_un, m_un_lock);//同時鎖定多個互斥量
  22. assert(std::tuple_size<decltype(g)>::value == 2);//測試是否鎖定2個

4.Lock介面卡/Lock概念檢查/lock函式

4.1Lock介面卡

幫助我們實現自己的執行緒安全的類。即當我們寫的類繼承了lock介面卡,那麼我們的類可以被lock_guard()/unique_lock()鎖定。

Lock_guard 與 unique_lock是模板類所以只要是滿足<LockAble>(含有lock/unlock/try_lock

的介面的類都可以使用它,實現原子操作等。

Lockable介面卡類就是為了方便我們實現Lockable的。

Basic_lockable_adapter 

最簡單介面,提供lockunlock

Lockable_adapter

基本介面,增加try_lock

Timed_lockable_adapter

增加try_lock_for/try_lock_until

Code:

  1. #include<iostream>
  2. #include<boost/thread/thread.hpp>
  3. #include<boost/atomic.hpp>//原子庫
  4. #include<boost/thread/lockable_adapter.hpp> //Lockable 介面卡
  5. #include<boost/thread/lock_factories.hpp>
  6. using namespace std;
  7. using namespace boost;
  8. class account : public lockable_adapter<mutex>
  9. {
  10. private:
  11. atomic<int> m_money_{ 0 }; //賬戶金額
  12. public:
  13. account(){}
  14. ~account(){}
  15. int sum()const
  16. {
  17. return m_money_;
  18. }
  19. void withdraw(int x)
  20. {
  21. m_money_ -= x;
  22. }
  23. void deposit(int x)//存錢
  24. {
  25. m_money_ += x;
  26. }
  27. void show()
  28. {
  29. cout << m_money_ << endl;
  30. }
  31. };
  32. int main()
  33. {
  34. account a;
  35. {
  36. auto g = make_unique_lock(a);
  37. a.deposit(100);
  38. a.show();
  39. a.withdraw(20);
  40. a.show();
  41. assert(a.sum() == 80);
  42. }
  43. {
  44. auto b = make_unique_lock(a, try_to_lock);
  45. if (b)
  46. {
  47. a.withdraw(a.sum());
  48. assert(a.sum() == 0);
  49. a.show();
  50. }
  51. }
  52. return 0;
  53. }

4.2.Lock概念檢查

概念檢查類保證我們在泛型程式設計時確保使用的模板引數滿足Lockable該每年,在編譯時保證程式的正確性。

4.3.Lock函式

Lock() / try_lock()操作mutex類似make_unique_locks() 可以一起鎖定多個Mutex,而且保證不會死鎖。他們不具有退出作用域自動解鎖,但他們在自身異常時會解除鎖定

所以一般配合unique_lockadopt_lock或者defer_lock鎖定選項,但暫時不鎖定互斥量.

Code:

  1. mutex m1, m2;
  2. {
  3. auto g1 = make_unique_lock(m1, adopt_lock);
  4. auto g2 = make_unique_lock(m2, adopt_lock);
  5. lock(m1, m2);
  6. }//unique_lock自動解鎖
  7. {
  8. auto g1 = make_unique_lock(m1, defer_lock);
  9. auto g2 = make_unique_lock(m2, defer_lock);
  10. try_lock(g1, g2);
  11. } //unique_lock自動解鎖

5.補:Shared_mutex.

一個特權--寫,多個普權--

Code:

  1. #include<iostream>
  2. #include<boost/thread/thread.hpp>
  3. #include<boost/chrono.hpp>
  4. #include<boost/bind.hpp>
  5. #include<boost/ref.hpp>
  6. using namespace std;
  7. using namespace boost;
  8. class rw_data
  9. {
  10. private:
  11. int m_x;
  12. shared_mutex rw_mu;
  13. public:
  14. rw_data() :m_x(0){}
  15. void write()
  16. {
  17. unique_lock<shared_mutex> g(rw_mu);
  18. ++m_x;
  19. }
  20. void read(int &x)
  21. {
  22. shared_lock<shared_mutex> g(rw_mu);
  23. x = m_x;
  24. }
  25. };
  26. mutex xzz;
  27. void writer(rw_data &d)
  28. {
  29. for (int i = 0; i < 2; ++i)
  30. {
  31. this_thread::sleep_for(chrono::microseconds(3000));
  32. d.write();
  33. }
  34. }
  35. void reader(rw_data &d)
  36. {
  37. int x;
  38. for (int i = 0; i < 10; i++)
  39. {
  40. this_thread::sleep_for(chrono::microseconds(5000));
  41. d.read(x);
  42. xzz.lock();
  43. cout << this_thread::get_id() << "reader:" << x << endl;
  44. xzz.unlock();
  45. }
  46. }
  47. int main()
  48. {
  49. //讀寫鎖機制
  50. rw_data d;
  51. thread_group pool;
  52. pool.create_thread(bind(writer, boost::ref(d)));
  53. pool.create_thread(bind(writer, boost::ref(d)));
  54. pool.create_thread(bind(reader, boost::ref(d)));
  55. pool.create_thread(bind(reader, boost::ref(d)));
  56. pool.create_thread(bind(reader, boost::ref(d)));
  57. pool.create_thread(bind(reader, boost::ref(d)));
  58. pool.join_all();
  59. std::system("pause");
  60. return 0;
  61. }