下面的代码是一点学习笔记,先记录一下,有时间的时候再过来把它整理一下。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<map>
#include<list>
#include<typeinfo>
#include<random>
#include<mutex>
#include<thread>
using namespace std;
#if 0
void main()
{
system("pause");
}
#endif
#if 0
void main()
{
string str = "asdfghjkl";
for (int i = 0; i < str.size(); i++)
{
cout << &str[i] << endl;
}
float a;
map<int, int> m;
cout << "******" << typeid(a).name() << endl;
char *chr = new char[100];
strcpy(chr, typeid(m).name());
cout << chr << endl;
system("pause");
}
#endif
#if 1
/*
lock与unlock一定要成对使用,否则就会出错。
lock_guard的构造函数中写进了lock
在析构函数中写进了unlock
所以lock_guard一般用于单独的一个函数中,起码在lock_guard的生命周期中它都
上锁的,一般将要上锁的部分单独拿出来写成函数,或者要对其作用域进行控制用{}
死锁:
至少有两把锁才能构成死锁
线程1是先锁锁1后锁锁2,线程2与线程1相反,这样就可能存在两个线程都在等待对方释放锁,而进入死锁。
死锁的一般解决方案:
1,只要保证两个互斥量上锁的次序一样
2,一次把所有的锁都上了,可以用std::lock()函数模板
该模板一次锁住两个或多个互斥量,不会因为上锁的次序问题导致死锁,如果有一个锁没有锁成功则将已经锁了的
马上释放掉,然后进入等到。
std::lock(my_mutex1,my_mutex2);
等价于:
my_mutex1.lock();
my_mutex2.lock();
但是这种还是需要两个unlock
3,是否可以用lock_guard和lock结合使用,这样就可以一次上多把锁,而且不用担心忘记是否?
写法为:
std::lock(my_mutex1,my_mutex2);
std::lock_guard<std::mutex> sbguard1(my_mutex1,std::adopt_lock);//std::adopt_lock这个参数就表示前面已经有上锁,这步就不执行上锁操作
std::lock_guard<std::mutex> sbguard2(my_mutex2,std::adopt_lock);
4,unique_lock是一个类模板,可以完全取代lock_guard,而且比lock_guard更加灵活
unique_lock同样也支持第二个参数,而且参数类型更丰富
std::unique_lock<std::mutex> sbguard(my_mutex,std::adopt_lock)//第二个参数起标记作用
std::adopt_lock:表示互斥量已经被lock了(必须提前把互斥量lock了,不然报错)
std::try_to_lock:程序会尝试使用mutex的lock去上锁,但是如果没有锁成功,程序也会立即返回,并不会阻塞
,用try_to_lock 的前提是不能先去上锁
std::defer_lock 前提是不能提前lock,使用后并没有给mutex加锁,初始化了一个没有加锁的mutex
这样就可以使用unique_lock的一些成员函数
std::unique_lock<std::mutex> sbguard(my_mutex,std::defer_lock);//创建一个没有加锁的my_mutex
//相当于把sbguard和my_mutex绑定在一起
sbguard.lock();//手动上锁,且不需要解锁
sbguard.unlock();//可以手动解锁,临时处理一些非共享代码,回来时再上锁就可以了
sbguard.try_lock();//尝试加锁,如果拿到锁则返回TRUE否则返回FALSE
sbguard.release();//返回它锁管理的mutex对象指针,并释放所有权,也就是说sbguard和mutex不在有关系
//如果mutex监管的对象已经加锁还没有解锁,还要手动解锁
std::unique_lock<std::mutex>sbguard(my_mutex);
std::mutex *ptx=sbguard.release();
..执行完共享代码后
ptx->unlock();
这里解释一下为什么需要手动unlock:
我们把锁头锁住的代码多少称为锁的粒度,粒度一般用粗细来描述
粒度细效率高;粒度粗效率低
要学会使用合适粒度的代码来保护代码,既保证不能遗漏对共享数据的保护,也要照顾代码执行的效率
5,unique_lock所有权的传递,一个unique_lock和一个mutex绑定在一起
std::unique_lock<std::mutex>sbguard(my_mutex);//sbguard拥有my_mutex的所有权,这个所有权可以转移但是不能复制,也就是说只有一个对象能操作mutex
std::unique_lock<std::mutex>sbguard2(sbguard);//不能进行复制
std::unique_lock<std::mutex>sbguard2(std::move(sbguard));//sbguard就指向空了,sbguard2就指向mutex2
还有一种方法可以转移所有权,需要定义一个转移一个函数
std::unique_lock<std::mutex> rtn_unique_lock(my_mutex1)
{
std::unique_lock<std::mutex> tmpguard(my_mutex);
return tmpguard;
//返回一个局部的unique_lock对象是可以的
//这种返回局部对象的方式会导致系统生成一个临时的unique_lock对象,并调用unique_lock的移动构造函数
}
std::unique_lock<std::mutex> sbguard2=rtn_unique_lock(my_mutex1);//创建一个对象来承接这个临时对象即可
*/
class Message{
public:
void in_message()
{
for (int i = 0; i < 100; i++)
{
/*my_mutex1.lock();
my_mutex2.lock();
my_message.push_front(i);
my_mutex1.unlock();
my_mutex2.unlock();*/
/*std::lock(my_mutex1, my_mutex2);
std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock);//std::adopt_lock这个参数就表示前面已经有上锁,这步就不执行上锁操作
std::lock_guard<std::mutex> sbguard2(my_mutex2, std::adopt_lock);
my_message.push_front(i);*/
std::lock(my_mutex1, my_mutex2);
std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock);//uniqu_lock完全可以替代lock_guard使用
//std::unique_lock<std::mutex> sbguard2(my_mutex2, std::adopt_lock);
std::unique_lock<std::mutex> sbguard2(my_mutex2, std::try_to_lock);
my_message.push_front(i);
cout << "向共享内存中存入数据:" << i << endl;
}
}
void out(int &ret)
{
my_mutex1.lock();
my_mutex2.lock();
if (!my_message.empty())
{
ret = my_message.front();
my_message.pop_front();
cout << "从共享内存中取出数据:" << ret<< endl;
}
my_mutex1.unlock();
my_mutex2.unlock();
}
void out_message()
{
//std::lock_guard<std::mutex> sbguard(my_mutex1);
for (int i = 0; i < 100; i++)
{
int ret;
out(ret);
}
}
private:
list<int > my_message;
mutex my_mutex1,my_mutex2;
};
/*
互斥量是一个是一个类对象,有成员函数lock和unlock
两者要成对使用
*/
int main()
{
Message m;
thread t_in(&Message::in_message,&m);
thread t_out(&Message::out_message,&m);
t_in.join();
t_out.join();
system("pause");
return 0;
}
#endif