前言

本章节主要介绍C++11的并发库中的 thread 线程这个类。但是目的并不是将这个类讲解清楚,而是主要是介绍一些常用的点。我们没有必要为了记忆而记忆,遗忘是很正常的事情,我们不知道接口的时候,就可以查阅文档:

  • 官方文档。可读性有点不高,但是新!
  • 小编常用文档。这个文档的可读性较高,小编比较喜欢在这上面查阅一些C++的遗忘的语法知识。但是这个文档局限性较高,只有C++11及以下的语法,并没有C++14/C++17的语法。

同时,如果觉得文档查阅低效,现在有很多的AI可以辅助学习:豆包、deepseek、kimi、……配合这些资源都能快速对这些接口上手!

1. thread

学习 Linux 系统的时候大家肯定对 thread 已经不陌生了。在使用原生线程库的时候,很重的一个硬伤就是:参数的传递。幸好:C++11退出了线程库,采用了面向对象的编程思想,包装了线程库,极大的便利了开发者。

如下是一些C++11线程库的一些简介:

  • thread 库底层是对各个系统的线程库进行封装(简单来说就是采用条件编译),如 Linux 下的 pthread 库和 Windows 下 Thread 库等,所以 C++11 thread 库的第⼀个特点是可以跨平台,第⼆个特点是 Linux 和 Windows 下提供的线程库都是面向过程的,C++11 thread是库面向对象的,并且融合了⼀些C++11语言特点,如右值引用的移动语义可变模板参数等,用起来会更好用⼀些。

  • 来看 thread 的几个构造函数

    在这里插入图片描述
    注意

    1. 空的构造:这是为了使用容器的时候,可以之间空构造一个节点。(例如:vector

    2. 传入一个可执行对象:常用的就是 lambda。这个是常用的方式

    3. 不支持拷贝构造。

    4. 支持移动构造,这也是为了配合一些容器的使用!

案例一:

int main()
{
	std::thread t1([]() {
		for (int i = 0; i < 10; ++i)
		{
			std::cout << i << std::endl;
		}
		});
	std::thread t2([]() {
		for (int i = 10; i < 20; ++i)
		{
			std::cout << i << std::endl;
		}
		});

	t1.join();
	t2.join();

	return 0;
}

显示器文件也是共享资源,存在临界资源的竞争问题。

案例二:

int main()
{
	std::vector<std::thread> v(5); //开5个线程的空间。这里就注定了要使用空的构造
	v.push_back(std::thread([]() {
		for (int i = 0; i < 10; ++i)
		{
			std::cout << i << std::endl;
		}
		}));

	for (auto& e : v)
	{
		if(e.joinable())
			e.join();
	}

	return 0;
}

使用 vector 来管理线程。配合容器的使用,我们更好地实现一个简易的线程池

下面还有这些方法,小编也不再做介绍了!

在这里插入图片描述

2. this_thread

在我们刚刚的案例中,有一个问题:我们想在我们线程内部获取我们的线程id怎么办呢?好像没有办法?这个时候 C++11 包装了一个命名空间this_thread。提供了很多的关于当前线程的方法

在这里插入图片描述

在这里插入图片描述

  1. yield:这个接口的使用还是挺有场景的。

    • 自旋锁的实现。在等待某个资源时,避免线程进入阻塞状态(可能导致上下文切换开销),而是通过循环 + yield () 的方式短暂等待。

    • 降低忙等待的 CPU 占用。当线程需要等待某个条件满足但又不适合使用条件变量时(如等待时间极短的情况),使用 yield () 可以减少 CPU 资源浪费。

    • 优先级调整。在某些情况下,当前线程执行的任务优先级较低,希望优先让其他重要线程执行时。

    但是也有注意:

    • yield() 只是一个提示,操作系统不一定会立即切换到其他线程

    • 过度使用 yield() 可能导致性能下降,因为频繁的线程切换会带来开销

    • 对于长时间等待的场景,应优先使用条件变量(std::condition_variable)而非 yield() + 循环的方式

  2. sleep_forsleep_until

    这两个函数的作用都是休眠当前线程。在一些场景下,我们不希望一个线程一直执行,但是没有成效。(死循环检测一些条件就绪)我们就可以给这样的线程设置一个休眠时间,从而把 CPU 资源交给其它线程避免进程切换的开销。

    同时,想要使用这两个类,不得不学会使用的一个库就是:chrono

2.1 chrono库

在这里插入图片描述

这个库支持了关于时间的很多操作:

  1. 测量代码执行时间。

  2. 时长转换与运算。

  3. 获取系统当前时间。

3demo:

#include <iostream>
#include <chrono>
#include <ctime>

int main()
{
    // 获取当前系统时间点
    auto now = std::chrono::system_clock::now();
    
    // 转换为time_t类型(传统C时间类型)
    std::time_t now_c = std::chrono::system_clock::to_time_t(now);
    
    // 格式化输出
    std::cout << "当前时间: " << std::ctime(&now_c);  // 例如: Wed Sep 26 10:00:00 2025
    
    return 0;
}

关键特性与优势:

  • 类型安全:不同时间单位的时长是不同类型,避免隐式转换错误。
  • 高精度:支持纳秒级计时(取决于系统硬件)
  • 灵活性:可自定义时间单位和存储类型。
  • 可移植性:统一接口屏蔽了不同系统的时间实现差异。

std::chrono 特别适合需要精确计时、时间间隔计算或跨平台时间处理的场景,如性能测试、定时器实现、事件调度等。

配合 this_thread 使用,伪代码demo:

int main()
{
	std::thread t1([]() {
		std::this_thread::sleep_for(std::chrono::seconds(30));
		//休眠三十秒
		while (true)
		{
			//做一些检测……
			
			//条件满足了
			// if(/*xxx*/) break;
		}
		});
	t1.join();
	return 0;
}

完。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐