QT(8)-线程锁

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);//休息一定的时长
相关推荐
biubiubiu07061 小时前
SpringBoot 3.5.4 整合Quartz 定时任务
java·spring boot·spring
mifengxing1 小时前
LeetCode热题100——字母异位词分组
java·算法·leetcode·职场和发展·哈希表·hot100
微三云、小叶2 小时前
排队免单系统底层设计:四种分配算法拆解,无预支资金的合规营销架构方案
java·前端·软件开发·商业模式·本地生活·商业思维
就叫_这个吧2 小时前
Java+MySQL+Mybatis+Junit4实现学生信息管理系统
java·mysql·mybatis
乐之者v2 小时前
xxl-job添加执行器
java
可乐ea2 小时前
【知识获取与分享社区项目 | 项目日记第 19 天】基于 Elasticsearch 实现关键词检索与业务权重排序
java·大数据·spring boot·mysql·elasticsearch·搜索引擎·全文检索
ZC跨境爬虫3 小时前
跟着 MDN 学 JavaScript day_2:JavaScript 初体验
开发语言·前端·javascript·学习·ecmascript
Jun6263 小时前
QT(3)-线程中使用控件
开发语言·qt
zzz_23683 小时前
【Spring】面试突击系列(一):IoC 与 DI 深度解析
java·spring·面试