
1.问题
测试发现,当在两个线程同时操作文件的时候,报出
ASSERT: "bytes <= bufferSize" in file tools\qringbuffer.cpp, line 113
2.线程锁
头文件
#include<mutex>
创建互斥量
std::mutex mtex;
mtex.lock();
/*进行操作*/
mtex.unlock();
使用互斥量
std::lock_guard<std::mutex> mlockg(mtex);//相当于智能指针 会自动帮你锁住和解锁 防止忘记解锁
示例
list<int> nums;
class A {
public:
void thread_workin()
{
//cout << "进入输入子进程" << endl;
mtex.lock();
for (int i = 0; i < 10000; i++)
{
nums.push_back(i);
}
mtex.unlock();
}
void thread_workout()
{
/*使用智能锁*/
//std::lock_guard<std::mutex> mlockg(mtex);//相当于智能指针 会自动帮你锁住和解锁 防止忘记解锁
/*将这一段数据锁住*/
mtex.lock();
//cout << "进入输出子进程" << endl;
for (int i = 0; i < 10000; i++)
{
if (!nums.empty())
{
int temp = nums.front();
cout << temp << " " << endl;
nums.pop_front();
}
else
{
cout << "队列中已经空了" << endl;
}
}
mtex.unlock();
}
private:
std::mutex mtex;
};
int main()
{
A a;
thread mobj1(&A::thread_workin,&a);
thread mobj2(&A::thread_workout, &a);
mobj1.join();
mobj2.join();
cout << "主进程已经结束" << endl;
return 0;
}
3.智能互斥量lock_guard
std::lock_guard<std::mutex> 智能互斥量对象名(互斥量对象名); 会自动调用lock和unlock
使用
class A {
private:
std::mutex mtex;//创建互斥量对象
vector<int> nums;
public:
//在需要上锁的地方创建
//线程入口函数
void func()
{
std::lock_guard<std::mutex> mlockg(mtex);
for(int i = 0;i<10;i++)
{
nums.push_back(i);
}
}
};
std::adopt_lock 方便在std::lock()函数值使用智能锁 (lock_guard和unique_lock的参数)
需要
std::adopt_lock是一个结构体对象 起一个标记作用 表示这个互斥量已经lock() 不需要在lock_guard中再lock
应该是在已经锁住的情况让lock_guard的创建不再在构造函数中lock 也就是不会再锁一遍
但是用std::adopt_lock参数之前必须先对这个互斥量lock 要不然会报错
std::mutex mtex1;
std::mutex mtex2;
std::lock(mtex1,mtex2);//此时已经同时锁了两个互斥量 为了防止我们忘记使用unlock 我们使用智能锁
std::lock_guard<std::mutex> mlockg1(mtex1,std::adopt_lock);//这样就不会重复锁第二遍 并且还能自动unlock
std::lock_guard<std::mutex> mlockg2(mtex2,std::adopt_lock);
原理
lock_guard是一个类对象 在创建的时候会调用自己的构造函数 构造函数里面会调用mtex的lock()函数
在该对象生命周期结束时会调用lock_guard的析构函数 此时会调用mtex的unlock()函数
所以我们是可以使用{}来决定这个lock_guard的生命周期的
4.std::unique_lock
unique_lock是一个类模板
正常使用时 unique_lock可以完全取代lock_guard 也就是lock_guard 用的地方 直接可以地换成unique_lock
unique_lock比lock_guard 更灵活 但是效率更低 内存占用更多
unique_lock参数
std::try::lock
尝试用mtex的lock()去锁定mtex 如果没有锁成功 会立即返回 并不会锁死
不能先lock
//mtex.lock();//如果先lock了 再try_to_lock就会卡死
std::unique_lock<std::mutex> muniquel(mtex,std::try_to_lock);
if(mtex.owns_lock())
{
/*表示拿到锁了*/
}
else
{
/*没拿到锁*/
}
std::defer_lock
不能先lock
初始化一个没有加锁的mutex
因为正常调用std::unique_lock muniquel(mtex);会直接给mtex加锁 所以有了这个参数
std::unique_lock<std::mutex> muniquel(mtex,std::defer_lock);//此时mtex是未上锁状态
muniquel.lock();
unique_lock成员函数
std::unique_lock<std::mutex> muniquel(mtex,std::defer_lock);//此时mtex是未上锁状态
muniquel.lock();//上锁
muniquel.unlock();//解锁
if(muniquel.try_lock())//尝试上锁
{
/*拿到锁了*/
}
/*释放所有权*/
std::mutex*ptx = muniquel.release();//返回他所管理的mutex对象指针 ,并释放所有权 此时muniquel就不会再自动解锁了 将权力给了ptx
ptx->unlock();
/*转移所有权*/
std::unique_lock<std::mutex> muniquel1(mtex);
std::unique_lock<std::mutex> muniquel2(std::move(muniquel1));//此时muniquel1指向空
std::lock()同时锁住多个互斥量
如果其中有一个互斥量没办法锁住 就会一直等着
会不停的尝试是否能同时锁住这些互斥量 要么都锁住 要么都不锁
如果有一个能锁住 另一个不能 则会解锁 掉锁住的锁
std::mutex mtex1;
std::mutex mtex2;
std::lock(mtex1,mtex2);
mtex1.unlock();
mtex2.unlock();
std::chrono::milliseconds dura();std::this_thread::sleep_for(dura);相当于sleep 让线程休息一下
std::chrono::milliseconds dura(20000);//单位是毫秒
std::this_thread::sleep_for(dura);//休息一定的时长