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:
- mutex mutex_thread_1;
- try
- {
- mutex_thread_1.lock();
- cout << "Do Something" << endl;
- mutex_thread_1.unlock();
- }
- catch (std::exception e)
- {
- //cout << << endl;;
- mutex_thread_1.unlock();
- }
- timed_mutex t_mutex_1;
- auto flag = t_mutex_1.try_lock_for(boost::chrono::milliseconds(100));
- if (flag)
- {
- cout << "訪問共享" << endl;
- t_mutex_1.unlock();
- }
- else
- {
- cout << "未獲得鎖,進行其他操作" << endl;
- }
2.Lock_guard()-- Mute的優秀輔助
作用:此類輔助鎖定互斥量,構造時鎖定,析構時解鎖,避免遺忘解鎖,也就是說在其作用域內他會一直鎖定要求的變數。
類似智慧指標?
附加擴充套件:with_lock_guard()藉助lock_guard()在函式中互斥使用某鎖定資源,(封裝函式用?)
- mutex mu;
- lock_guard<mutex> g(mu);//作用域內自動智慧加鎖/解鎖
- cout << "Do something" << endl;
- timed_mutex t_mu;
- if (mu.try_lock_for(boost::chrono::microseconds(100)))
- {
- lock_guard<timed_mutex> g(t_mu,adopt_lock);//不會再次加鎖
- cout << "Do something" << endl;
- }
[cpp] view plain copy print?- <code class="language-cpp">#include <boost/thread/with_lock_guard.hpp></code>
#include <boost/thread/with_lock_guard.hpp>
- #bind()封裝用
- //with_lock_guard
- mutex fmu;
- string name = "ZGJ";
- int rul = with_lock_guard(fmu, bind(Alloa,argv1,argv2...));//新增引數需謹慎,為Boost中引數型別,Alloa為函式,argv為其引數
- cout << rul << endl;
- With_lock_guard(lockable& m, Function && fun, Args &&...args) 類似於
- {
- Lock_guard<lockable> g(m);
- Return func(argc...)
- }
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:
- #include<boost\thread\lock_factories.hpp>
- mutex m_un_lock;
- {//此類大括號活用作用域,供make_unique_lock析構使用。
- auto g = make_unique_lock(m_un_lock);//工廠函式鎖定互斥量
- assert(g.owns_lock());//斷言 -- 已經鎖定
- cout << "Do something" << endl;
- }
- {
- auto g = make_unique_lock(m_un_lock, defer_lock);//暫不鎖定互斥量
- assert(!g);// 斷言 -- 沒有鎖定
- assert(g.try_lock());//嘗試鎖定
- assert(g);//斷言 -- 已經鎖定
- cout << "Do something" << endl;
- }
- timed_mutex t_mu_un;
- {
- auto g = unique_lock<timed_mutex>(t_mu_un, boost::chrono::milliseconds(100)); //限時100MS嘗試鎖定
- if (g)
- {
- cout << "Lock timed mutex" << endl;
- }
- }
- auto g = make_unique_locks(t_mu_un, m_un_lock);//同時鎖定多個互斥量
- 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
最簡單介面,提供lock與unlock
Lockable_adapter
基本介面,增加try_lock
Timed_lockable_adapter
增加try_lock_for/try_lock_until
Code:
- #include<iostream>
- #include<boost/thread/thread.hpp>
- #include<boost/atomic.hpp>//原子庫
- #include<boost/thread/lockable_adapter.hpp> //Lockable 介面卡
- #include<boost/thread/lock_factories.hpp>
- using namespace std;
- using namespace boost;
- class account : public lockable_adapter<mutex>
- {
- private:
- atomic<int> m_money_{ 0 }; //賬戶金額
- public:
- account(){}
- ~account(){}
- int sum()const
- {
- return m_money_;
- }
- void withdraw(int x)
- {
- m_money_ -= x;
- }
- void deposit(int x)//存錢
- {
- m_money_ += x;
- }
- void show()
- {
- cout << m_money_ << endl;
- }
- };
- int main()
- {
- account a;
- {
- auto g = make_unique_lock(a);
- a.deposit(100);
- a.show();
- a.withdraw(20);
- a.show();
- assert(a.sum() == 80);
- }
- {
- auto b = make_unique_lock(a, try_to_lock);
- if (b)
- {
- a.withdraw(a.sum());
- assert(a.sum() == 0);
- a.show();
- }
- }
- return 0;
- }
4.2.Lock概念檢查
概念檢查類保證我們在泛型程式設計時確保使用的模板引數滿足Lockable該每年,在編譯時保證程式的正確性。
4.3.Lock函式
Lock() / try_lock()操作mutex類似make_unique_locks() 可以一起鎖定多個Mutex,而且保證不會死鎖。他們不具有退出作用域自動解鎖,但他們在自身異常時會解除鎖定
所以一般配合unique_lock的adopt_lock或者defer_lock鎖定選項,但暫時不鎖定互斥量.
Code:
- mutex m1, m2;
- {
- auto g1 = make_unique_lock(m1, adopt_lock);
- auto g2 = make_unique_lock(m2, adopt_lock);
- lock(m1, m2);
- }//unique_lock自動解鎖
- {
- auto g1 = make_unique_lock(m1, defer_lock);
- auto g2 = make_unique_lock(m2, defer_lock);
- try_lock(g1, g2);
- } //unique_lock自動解鎖
5.補:Shared_mutex.
一個特權--寫,多個普權--讀
Code:
- #include<iostream>
- #include<boost/thread/thread.hpp>
- #include<boost/chrono.hpp>
- #include<boost/bind.hpp>
- #include<boost/ref.hpp>
- using namespace std;
- using namespace boost;
- class rw_data
- {
- private:
- int m_x;
- shared_mutex rw_mu;
- public:
- rw_data() :m_x(0){}
- void write()
- {
- unique_lock<shared_mutex> g(rw_mu);
- ++m_x;
- }
- void read(int &x)
- {
- shared_lock<shared_mutex> g(rw_mu);
- x = m_x;
- }
- };
- mutex xzz;
- void writer(rw_data &d)
- {
- for (int i = 0; i < 2; ++i)
- {
- this_thread::sleep_for(chrono::microseconds(3000));
- d.write();
- }
- }
- void reader(rw_data &d)
- {
- int x;
- for (int i = 0; i < 10; i++)
- {
- this_thread::sleep_for(chrono::microseconds(5000));
- d.read(x);
- xzz.lock();
- cout << this_thread::get_id() << "reader:" << x << endl;
- xzz.unlock();
- }
- }
- int main()
- {
- //讀寫鎖機制
- rw_data d;
- thread_group pool;
- pool.create_thread(bind(writer, boost::ref(d)));
- pool.create_thread(bind(writer, boost::ref(d)));
- pool.create_thread(bind(reader, boost::ref(d)));
- pool.create_thread(bind(reader, boost::ref(d)));
- pool.create_thread(bind(reader, boost::ref(d)));
- pool.create_thread(bind(reader, boost::ref(d)));
- pool.join_all();
- std::system("pause");
- return 0;
- }