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++线程同步——阻塞线程的方法

一般,使线程阻塞我们可以使用 while(condition); for(;condition;); 等循环条件使之线程内语句执行在循环处无法向下继续执行,但这样并不是真正意义上的线程阻塞,当前线程仍然在执行,只是在循环语句处不断空耗CPU

在C中有信号量、互斥量、条件变量、读写锁等可用于线程同步,他们都有对应的可以使之线程阻塞的方法。

例如C的信号量。C头文件 <semaphore.h>中

  • sem_wait() 会阻塞当前线程
  • sem_trywait() 返回错误而不是阻塞调用
  • sem_timedwait() sem_timedwait的abs_timeout参数指定了调用应该阻塞的时间限制

在C++中主要有以下方法:
信号量
信号量 (semaphore) 是一种轻量的同步原件,用于制约对共享资源的并发访问。在可以使用两者时,信号量能比条件变量更有效率。

定义于头文件 <semaphore>
counting_semaphore 实现非负资源计数的信号量
binary_semaphore 仅拥有二个状态的信号量(typedef)

其中

  • acquire 减少内部计数器或阻塞到直至能如此
  • try_acquire 尝试减少内部计数器而不阻塞
  • try_acquire_for 尝试减少内部计数器,至多阻塞一段时长
  • try_acquire_until 尝试减少内部计数器,阻塞直至一个时间点

互斥
互斥算法避免多个线程同时访问共享资源。这会避免数据竞争,并提供线程间的同步支持。

定义于头文件 <mutex>

  • lock 锁定互斥,若互斥不可用则阻塞 ,其中lock可锁定多个mutex对象,并内置免死锁算法避免死锁。
  • try_lock 尝试锁定互斥,若互斥不可用则返回 (不阻塞)
  • unlock 解锁互斥

通常不直接使用 std::mutex ,一般使用 std::unique_lock 、 std::lock_guard 或 std::scoped_lock 互斥器管理器使用。

  • lock_guard 实现严格基于作用域的互斥体所有权包装器
  • scoped_lock 用于多个互斥体的免死锁 RAII 封装器
  • unique_lock 实现可移动的互斥体所有权包装器

条件变量
条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续。条件变量始终关联到一个互斥。

定义于头文件 <condition_variable>

condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。

有意修改变量的线程必须

  1. 获得 std::mutex (常通过 std::lock_guard )
  2. 在保有锁时进行修改
  3. 在 std::condition_variable 上执行 notify_one 或 notify_all (不需要为通知保有锁)
    即使共享变量是原子的,也必须在互斥下修改它,以正确地发布修改到等待的线程。

由上可得,条件变量在线程同步时,需要获得互斥量才能进行。而 unique_lock 这个互斥器管理器允许自由的unlock,所以一般条件变量与unique_lock一起使用。

  • wait 、 wait_for 或 wait_until ,等待操作自动释放互斥,并悬挂线程的执行(阻塞)。
    在这里插入图片描述

Future
标准库提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常。这些值在共享状态中传递,其中异步任务可以写入其返回值或存储异常,而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。

  • get 返回结果 ,get 方法等待直至 future 拥有合法结果并(依赖于使用哪个模板)获取它。它等效地调用 wait() 等待结果。(阻塞
  • wait 等待结果变得可用 。阻塞直至结果变得可用。调用后 valid() == true 。
  • wait_for 等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。 阻塞直至经过指定的 timeout_duration,或结果变为可用
  • wait_until 等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。阻塞直至抵达指定的 timeout_time ,或结果变为可用

this_thread
在this_thread命名空间下,有this_thread::sleep_for、this_thread::sleep_until、this_thread::yield 三个方法。

其中前两个可以通过让线程睡眠一段时间而达到阻塞线程的目的。

后者,可以通过一定的条件使得当前线程让度给其他线程达到阻塞的目的。while (condition) this_thread::yield();

原子操作(CAS)

此外,使用原子量实现自旋锁,也可以在一定时间内阻塞线程。

class CAS	// 自旋锁
{
private:
	std::atomic<bool> flag;	// true 加锁、false 无锁
public:
	CAS() :flag(true) {}   // 注意这里初始化为 true,因此,第一次调用 lock()就会阻塞
	~CAS() {}
	CAS(const CAS&) = delete;
	CAS& operator=(const CAS&) = delete;

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

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 5:40:01-

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