多线程基础篇2-------<mutex>

来源:互联网 发布:painter自动上色软件 编辑:程序博客网 时间:2024/06/10 17:54
<mutex>


相关全局类:

1.std::mutex //普通锁
2.std::recursive_mutex//递归锁
3.std::time_mutex//时间锁
4.std::recursive_time_mutex//递归时间锁

以下两个模板类第一个参数只能是mutex
5.std::lock_guard<>
6.std::unique_lock<>//lock_guard、unique_lock都可以用1/[4]任意一种mutex来初始化模板
其他类:
7.std::once_flag<condition_variable>
8.std::defer_lock_t
9.std::adopt_lock_t
10.std::try_to_lock_t
所谓的线程锁:是为了避免线程之间对系统资源的竞争(如全局变量,显存,打印机,键盘等等等等等)
而mutex的存在的意义即在于:它能锁住(保护)临界区,同步线程(临界区:公共的系统资源)

1.mutex:成员函数及其应用:
  members_functions:
1.obj.lock();
2.obj.unlock();
3.obj.native_handle();
4.obj.operator=
5.obj.try_lock();

6.obj.~_Mutex_base();

#include<iostream>#include<thread>//线程库#include<chrono>//Date and time utilities 、、时间和日期工具库#include<mutex>using std::cin;using std::cout;using std::endl;int common_int;std::mutex mut;//资源锁,初始状态为开锁状态void th_fun(){for (int i = 0; i < 10; i++){mut.lock();cout << common_int++ << endl << endl;;common_int++;mut.unlock();}cin.ignore();}int main(){std::thread t(th_fun);t.detach();//非阻塞实现线程for (int i = 0; i < 10; i++){mut.lock();cout << common_int++ << endl;mut.unlock();}return 0;}




2.recursive_mutex
  members_functions:
1.obj.lock();
2.obj.unlock();
3.obj.native_handle();
4.obj.operator=
5.obj.try_lock();
6.obj.~_Mutex_base();

区别于mutex:可以对同一对象进行多重锁,(注意对应多重解锁)

#include<iostream>#include<thread>//线程库#include<chrono>//Date and time utilities 、、时间和日期工具库#include<mutex>using std::cin;using std::cout;using std::endl;int common_int;std::recursive_mutex mut;//资源锁,初始状态为开锁状态void recursive(){mut.lock();cout << common_int++ << endl;mut.unlock();}void th_fun(){for (int i = 0; i < 10; i++){mut.lock();cout << common_int++ << endl << endl;;common_int++;recursive();mut.unlock();}cin.ignore();}int main(){std::thread t(th_fun);t.detach();//非阻塞实现线程for (int i = 0; i < 10; i++){mut.lock();cout << common_int++ << endl;mut.unlock();}return 0;}


后面两个类不予实例


3.timed_mutex:
members_functions:
1.obj.lock();
2.obj.unlock();
3.obj.native_handle();
4.obj.operator=
5.obj.try_lock();
6.obj.~_Mutex_base();
7.obj.try_lock_for();
8.obj.try_lock_until();
//special:新增加了两个时间条件阻塞函数:配合chrono使用


4.recursive_time_mutex:
members_functions:
1.obj.lock();
2.obj.unlock();
3.obj.native_handle();
4.obj.operator=
5.obj.try_lock();
6.obj.~_Mutex_base();
7.obj.try_lock_for();
8.obj.try_lock_until();
//special:增加两个时间阻塞函数,且支持递归锁



5.lock_guard<>基于mutex的封装类:
members_functions:
boost::实现

template<typename Mutex>
class lock_guard
{
private:
Mutex& m;


explicit lock_guard(lock_guard&);
lock_guard& operator=(lock_guard&);
public:
explicit lock_guard(Mutex& m_):
m(m_)
{
m.lock();
}
lock_guard(Mutex& m_,adopt_lock_t):
m(m_)
{}
~lock_guard()
{
m.unlock();
}
};

只有两个方法:即构造函数和析构函数:

adopt_lock用来在使用多锁锁定同一临界区时,配合std::lock全局函数避免deadline


#include<iostream>#include<thread>//线程库#include<chrono>//Date and time utilities 、、时间和日期工具库#include<mutex>using std::cin;using std::cout;using std::endl;int common_int;std::mutex mut;//资源锁,初始状态为开锁状态void th_fun(){for (int i = 0; i < 10; i++){std::lock_guard<std::mutex> lock(mut);//mut.lock();//lock_guard<>的对象初始状态为上锁状态cout << common_int++ << endl << endl;;common_int++;//mut.unlock();}cin.ignore();}int main(){std::thread t(th_fun);t.detach();//非阻塞实现线程for (int i = 0; i < 10; i++){std::lock_guard<std::mutex> lock(mut);//mut.lock();cout << common_int++ << endl;//mut.unlock();}return 0;}





unique_lock<>:基于mutex的封装:
memmbers_functions:
·constructor://构造函数

unique_lock();  
unique_lock( unique_lock&& other );  //std::move()
explicit unique_lock( mutex_type& m );//最常用
unique_lock( mutex_type& m, std::defer_lock_t t );//初始化是为unlock状态的mutex
unique_lock( mutex_type& m, std::adopt_lock_t t );//假设已拥有mutex:其实就是构造是不锁同defer
unique_lock( mutex_type& m, std::try_to_lock_t t );//通过调用mutex.try_lock();实现非阻塞(如果当前线程已拥有mutex且不是递归mutex会引起未定义行为)
template< class Rep, class Period >//通过调用mutex.try_lock_for();实现此函数相同效果
unique_lock(mutex_type& m, 
const std::chrono::duration<Rep,Period>& timeout_duration);
template< class Clock, class Duration >//通过调用mutex.try_lock_until();达到相同效果
unique_lock(mutex_type& m, 
const std::chrono::time_point<Clock,Duration>& timeout_time);

·members_functions:

obj.mutex()//返回关联的mutex指针,否则返回NULL
obj.owns_lock();//检查关联的mutex是否锁住;返回 是/否//类似于thread.joinable();
obj.operator bool();//调用obj.owns_lock();效果相同
obj.lock();
obj.unlock();
obj.try_lock();
obj.try_lock_for();
obj.try_lock_until();
obj.operator=();//std::move();其一构造函数
obj.release();//释放相关互斥量(放弃锁)
obj.swap();
obj.~unique();

小结一下:在加时条件阻塞中unique_lock在使用中有点冗杂(笔者浅见)


lock_guard<>、unique_lock<>都是采用RAII手法对mutex的封装管理:

其目的是:
实现在对象构造是对mutex加锁,在析构时自动解锁,这样一个栈对象保证了在异常情形下mutex可以在lock_guard,unique_lock对象析构被解锁,




关于mutex的全局函数:

1.std::lock();
2.std::try_lock();//和std::lock();类似
3.std::call_once();

std::lock();

template <class Mutex1, class Mutex2, class... Mutexes>  void lock (Mutex1& a, Mutex2& b, Mutexes&... cde);
//应当注意的是此函数的参数只能是*_mutex的类型,而不能是lock_guard<>或unique_lock<>

for instance:
#include<iostream>#include<thread>//线程库#include<chrono>//Date and time utilities 、、时间和日期工具库#include<mutex>using std::cin;using std::cout;using std::endl;int common_int;std::mutex mut1,mut2;//资源锁,初始状态为开锁状态void th_fun(){for (int i = 0; i < 10; i++){//当对同一资源需要多次上锁时(如需要对两个存在关联的资源上锁)std::lock(mut1,mut2);cout << common_int++ << endl << endl;common_int++;mut1.unlock();mut2.unlock();//mut.unlock();}cin.ignore();}int main(){std::thread t(th_fun);t.detach();//非阻塞实现线程for (int i = 0; i < 10; i++){std::lock(mut1, mut2);cout << common_int++ << endl;mut1.unlock();mut2.unlock();//mut.unlock();}return 0;}


//当有需要对同一资源进行上多个锁mutex时,需要对多个所进行有序上锁或用std::lock()一次锁定全部mutex。以防止死锁的产生

注意返回值:

试图同时对多个mutex上锁,成功返回-1
失败返回为上锁的muex对象个数


3.std::call_once();

template <class Fn, class... Args>
void call_once (once_flag& flag, Fn&& fn, Args&&... args);

for instance:http://www.cplusplus.com/reference/mutex/call_once/

// call_once 只执行一次(应该是设置标志量来预处理执行次数)#include <iostream>      #include <thread>         #include <chrono>         #include <mutex>          int winner;void set_winner(int x) { winner = x; }std::once_flag winner_flag;void wait_1000ms(int id) {for (int i = 0; i<1000; ++i)std::this_thread::sleep_for(std::chrono::milliseconds(1));std::call_once(winner_flag, set_winner, id);}int main(){std::thread threads[10];for (int i = 0; i<10; ++i)threads[i] = std::thread(wait_1000ms, i + 1);std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";for (auto& th : threads) th.join();std::cout << "winner thread: " << winner << '\n';return 0;}





关于deadline:

class person
{
int salary;
std::mutex mut;
public:
person(int s):salary(s){}
};




main()
{
//person a(2000),b(20000);//未对a,b互斥传递
std::thread t1(transfer1[,...]);//先简化参数传递,概述std::lock();的存在目的
std::thread t2(transfer2[,...]);
t1.join();
t2.join();
}
void transfer1()
{
a.mut.lock(); //******************b.mut.lock();a.mut.lock();
b.mut.lock(); //std::lock(a.mut,b.mut)
a.salary+=b.salary;//例子不是很恰当(想起以前看过一个银行转账加以简化的)
a.mut.unlock();
b.mut.unlock();
}
void transfer2()
{
a.mut.lock(); //*************************
b.mut.lock(); //std::lock(a.mut,b.mut)
a.salary+=b.salary;//
a.mut.unlock();
b.mut.unlock();
}


如果前后两个线程的上锁的顺序不同,且恰好形成一个线程锁住一个mutex,就会形成石锁deadline


<笔者水平有限,如有错误,敬请指正>

原创粉丝点击