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;
}
#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_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;
}
因篇幅问题不能全部显示,请点此查看更多更全内容