IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++线程二 -> 正文阅读

[C++知识库]c++线程二

接上篇!

其实用mutex的lock()、unlock(), 当然更好用lock_guard(),这些基本能满足我们的应用需求,且容易理解。

一、unique_lock 相比lock_gaurd有一些更灵活的用法

主要体现在unique_lock的参数和成员函数上。如下一目了然,不再举例子。

unique_lock<mutex> uniqeLock(mu, std::adopt_lock);//同lock_guard, 指示不加锁,前提是mutex已经加锁
unique_lock<mutex> uniqeLock(mu, std::try_to_lock);//尝试加锁,用在获取不到锁时执行一些其他操作
unique_lock<mutex> uniqeLock(mu, std::defer_lock); //不加锁,且mutex尚未锁定,配合成员函数使用
uniqeLock.try_lock();  //同参数std::try_to_lock
uniqeLock.owns_lock(); //返回bool,表明是否拥有锁
uniqeLock.release();   //返回mutex,解除unique_lock与mutex的绑定,unique_lock为空

其次,我们常用的用法是unique_lock的控制粒度很细。

unique_lock在析构时会自动判断是否需要解锁:

unique_lock<mutex> ulock(mu);
//执行一些操作
ulock.unlock();  //我们可以随时unlock

ulock.lock();
//执行另外的操作

//不用unlock,会自动判断

二、以上的lock_guard、unique_lock用法都是基于mutex,

除此之外还有std::recursive_mutex和std::timed_mutex

1、recursive_mutex:递归互斥锁,相对于mutex的互斥锁

mutex myMutex;
void fun1()
{
	myMutex.lock();
	fun2();             //同样fun2中也需要锁,这种情况mutex显然不能胜任
	//线程1操作....
	myMutex.unlock();
}
void fun2()
{
	myMutex.lock();
	//线程2操作....
	myMutex.unlock();
}

int main()
{
	myMutex.lock();
	fun1();           //调用fun1,但mutex只能lock一次
	myMutex.unlock();

	return 0;
}

这种情况,只能用recursive_lock,能递归加锁,用于这种在同一线程嵌套调用加锁的情况。

即同一线程内lock或try_to_lock成功后开始占有锁,并可以多次lock,直到匹配到同样多的unlock后释放锁。早占有期间,其他线程lock会阻塞!

当然同mutex一样,最好是配合lock_guard和unique_lock使用。

2、std::timed_mutex 在一定时期内尝试获取锁,获取到锁就返回。

1、try_lock_for类似与unique_lock<mutx> uLock(mu, std::try_to_lock);

void fun2()
{
	while (true)
	{
		if (tMutex.try_lock_for(chrono::seconds(1)))
		{
			cout << "fun2 开始执行" << endl;
			tMutex.unlock();
		}
		else
		{
			cout << "fun2 没获取锁" << endl;
		}
	}
}

2、try_lock_until()

tMutex.try_lock_until(chrono::steady_clock::now()+10s)

3、当然同mutex,超时锁也有递归版本 :recursive_timed_mutex

二、条件变量condition_variable

互斥锁是用来防止竞争问题,条件变量是解决“线程同步”问题。一个线程处理完后,通知另外的线程处理。

1、wait()、? notify_one()、notify_all()

对wait()的使用,详见代码的注释,因为只要通知一个线程,所以用notify_one()通知。

class A
{
public:
	void inQueueMsg()
	{	
		for (int i = 0; i < 100000; i++)
		{
			unique_lock<mutex> uniqueLock(mu);
			cout << "线程id:" << this_thread::get_id() << " 插入数据" << endl;
			msgQueue.push(i);
			condv.notify_one();
		} 
	}
	void outQueueMsg()
	{
		for (int i = 0; i < 100000; i++)
		{
			unique_lock<mutex> uniqLock(mu);
			condv.wait(uniqLock, [this]() {  //wait有两个重载 分别为1个参数和两个参数,都必须用unique_lock
				if (msgQueue.empty())        //wait会阻塞线程,直到收到notify信号,此时的阻塞会释放拿到的锁,并进入睡眠
					return false;            //收到notify信号,会再次尝试获取锁,获取后若没有第二个参数则走下去,
				return true;                 //若有第二个参数,则判断,为真走下去,为假则再次释放锁,进入睡眠
			});
			//走到此处说明非空,不用判断
			int m = msgQueue.front();
			msgQueue.pop();
			cout << "outQueueMsg线程id:" << this_thread::get_id << " 读出数据:" << m << endl;
		}
	}
private:
	queue<int> msgQueue;
	mutex mu;
	condition_variable condv;
};

int main()
{
	A ac;
	thread t1(&A::outQueueMsg, &ac);
	thread t2(&A::inQueueMsg, &ac);
	t1.join();
	t2.join();
	
	return 0;
}

notify_one()只会唤醒一个wait的线程,此线程尝试去拿锁,拿不到则一直尝试拿;

nofity_all()唤醒所有wait的线程,所有线程都会去拿锁,但只有一个拿到,所以会“惊群”,其他拿不到锁的都会一直尝试拿锁!

另外,如果发送notify时,其他线程没在wait上阻塞,则此次notify不会产生任何作用(notify信号不会被储存,而是直接消失)。

三、原子操作

因为这种互斥的情况,c++标准增加原子操作,std::atomic<>类模板,但只能是针对内置普通变量,所以一般只用在计数上。

std::atomic<int> g_count = 0;
void func()
{
	for (int i = 0; i < 100000; i++)
		g_count++;   //不需互斥,因为本身是原子操作,执行时cpu不会调度
}
int main()
{
	thread t1(func);
	thread t2(func); //多个线程对g_count进行操作
	t1.join();
	t2.join();
	cout << "g_count=" << g_count << endl;
	
	return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:20:07  更:2022-03-22 20:22:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:09:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码