【C++多线程】thread

embedded/2025/3/20 23:17:30/

C++中的std::thread是C++11引入的线程库的一部分,提供了创建和管理线程的能力。它封装了操作系统的线程接口,使得在C++中更方便地进行多线程编程。


1. std::thread 的定义

std::thread 类位于<thread>头文件中,定义在std命名空间下,用于表示一个独立执行的线程对象。其基本声明如下:

#include <thread>

std::thread 可以传递各种类型的参数,但要注意:
默认按值传递,如果要传引用,用 std::ref(x)。
移动对象用 std::move,避免不必要的拷贝。
成员函数必须传对象指针(&obj)。


2. std::thread 的构造函数

std::thread 提供了多个构造函数,允许不同方式创建线程。

(1) 默认构造函数

std::thread();
  • 创建一个空的std::thread对象,不与任何可执行线程关联。
#include <iostream>
#include <thread>int main() {std::thread t;  // 默认构造,不与任何线程关联std::cout << "t is joinable? " << t.joinable() << std::endl; // 输出 0(false)return 0;
}

(2) 可调用对象构造

template< class Function, class... Args >
explicit thread(Function&& f, Args&&... args);
  • 传入一个可调用对象(函数、函数对象、lambda 等)和参数,创建一个新的线程。
#include <iostream>
#include <thread>void func(int x) {std::cout << "Thread function with arg: " << x << std::endl;
}int main() {std::thread t(func, 10); // 创建线程并执行 func(10)t.join();  // 等待线程执行完毕return 0;
}

(3) 移动构造函数

thread(thread&& other) noexcept;
  • std::thread不可拷贝的,但可以移动
  • 该构造函数接收另一个std::thread对象,并接管其线程。
#include <iostream>
#include <thread>void func() {std::cout << "Thread running\n";
}int main() {std::thread t1(func);std::thread t2 = std::move(t1); // t1移动到t2,t1不再管理线程t2.join();return 0;
}

(4) 拷贝构造(删除)

thread(const thread&) = delete;
  • std::thread对象不能被拷贝,因为线程的所有权是唯一的。
  • 这样设计是为了避免多个std::thread对象管理同一个线程,导致未定义行为。
#include <thread>void func() {}int main() {std::thread t1(func);// std::thread t2 = t1; // ❌ 错误,不能拷贝return 0;
}

3. std::thread 的常用成员函数

(1) join() - 等待线程结束

void join();
  • 阻塞调用线程,直到目标线程执行完毕。
  • 必须在可联结的线程上调用,否则会导致异常。
#include <iostream>
#include <thread>void func() {std::cout << "Thread running\n";
}int main() {std::thread t(func);t.join();  // 等待线程执行完毕return 0;
}

(2) detach() - 分离线程

void detach();
  • 让线程在后台运行,与std::thread对象分离。
  • 线程对象会立即销毁,但线程继续执行,执行完毕后自动释放资源。
#include <iostream>
#include <thread>
#include <chrono>void func() {std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Thread finished\n";
}int main() {std::thread t(func);t.detach();  // 线程进入后台std::cout << "Main thread continues...\n";std::this_thread::sleep_for(std::chrono::seconds(3)); // 主线程等待return 0;
}

注意:如果主线程退出而分离线程还未执行完,可能会导致未定义行为。因此应谨慎使用detach()


(3) joinable() - 判断线程是否可联结

bool joinable() const noexcept;
  • 如果线程对象管理一个有效线程,则返回true
std::thread t(func);
if (t.joinable()) {t.join();
}

(4) get_id() - 获取线程ID

std::thread::id get_id() const noexcept;
  • 获取线程的唯一ID。
#include <iostream>
#include <thread>void func() {std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
}int main() {std::thread t(func);t.join();return 0;
}

(5) native_handle() - 获取操作系统的线程句柄

native_handle_type native_handle();
  • 获取线程的原生句柄,可用于底层线程操作(如设置优先级等)。

(6) hardware_concurrency() - 获取硬件支持的线程数

static unsigned int hardware_concurrency() noexcept;
  • 返回系统建议的并发线程数。
#include <iostream>
#include <thread>int main() {std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << std::endl;return 0;
}

4. std::thread 的用法示例

(1) 使用Lambda表达式

#include <iostream>
#include <thread>int main() {std::thread t([] {std::cout << "Lambda thread running\n";});t.join();return 0;
}

(2) 线程数组

#include <iostream>
#include <thread>
#include <vector>void func(int i) {std::cout << "Thread " << i << " started\n";
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 5; ++i) {threads.emplace_back(func, i);}for (auto& t : threads) {t.join();}return 0;
}

总结

  • std::thread 不能拷贝,但可以移动。
  • 使用join()等待线程结束,使用detach()分离线程。
  • 使用joinable()检查线程是否可联结。
  • 使用get_id()获取线程ID。
  • hardware_concurrency()获取系统支持的线程数。

多线程编程需要注意数据同步,否则可能导致数据竞争(race condition)等问题。可以使用std::mutexstd::condition_variable等同步机制来解决这些问题。


http://www.ppmy.cn/embedded/173973.html

相关文章

mac npm run dev报错 error:0308010C:digital envelope routines::unsupported

并且提示 Unsupported engine { npm WARN EBADENGINE package: achrinza/node-ipc9.2.2, npm WARN EBADENGINE required: { node: 8 || 10 || 12 || 14 || 16 || 17 }, npm WARN EBADENGINE current: { node: v18.18.0, npm: 9.8.1 } npm WARN EBADENGINE } package.jso…

2024华东师范大学计算机复试上机真题

2024华东师范大学计算机复试机试真题 2023华东师范大学计算机复试机试真题 2022华东师范大学计算机复试机试真题 2024华东师范大学计算机复试上机真题 2023华东师范大学计算机复试上机真题 2022华东师范大学计算机复试上机真题 在线评测&#xff1a;传动门&#xff1a;pgcode…

Leetcode 刷题笔记1 图论part01

图论的基础知识&#xff1a; 图的种类&#xff1a; 有向图&#xff08;边有方向&#xff09; 、 无向图&#xff08;边无方向&#xff09;、加权有向图&#xff08;边有方向和权值&#xff09; 度&#xff1a; 无向图中几条边连接该节点&#xff0c;该节点就有几度&#xff1…

SpringData Elasticsearch:索引管理与全文检索

文章目录 引言一、Spring Data Elasticsearch基础配置二、实体映射与索引定义三、索引管理操作四、文档管理与CRUD操作五、高级全文检索实现六、聚合与统计分析七、最佳实践与性能优化总结 引言 Elasticsearch作为一款强大的搜索引擎&#xff0c;被广泛应用于全文检索、日志分…

虚幻基础:移动组件

文章目录 移动组件&#xff1a;角色的移动信息和移动控制walk&#xff1a;行走falling&#xff1a;跳跃&下落 通用设置重力&#xff1a;模式通用重力max acceleration&#xff1a;模式通用加速度 walk制动降速行走&#xff1a;速度超过最大速度时的减速力 falling空气控制空…

软链接 使用笔记 linux命令 if判断

目录 1>0判断怎么写&#xff1a; 1. 使用 [ ] 进行数值比较&#xff1a; 2. 使用 (( )) 进行数学运算&#xff1a; 3. 使用 [[ ]]&#xff08;主要用于字符串比较&#xff0c;不推荐用于数学运算&#xff09;&#xff1a; 软链接 使用笔记 1>0判断怎么写&#xff1a…

BSides-Vancouver-2018 ftp匿名访问、hydra爆破22端口、nc瑞士军刀、提权

BSides-Vancouver-2018 ftp匿名访问、hydra爆破22端口、nc瑞士军刀、提权 一、信息收集 2025.3.15 AM 08:50 1、主机发现 arp-scan -l nmap -sn 192.168.66.24/02、端口扫描 简略扫描 nmap -sS -sV 192.168.66.183 简单扫描端口21/tcp open ftp vsftpd 2.3.5 22/tcp …

Python语言的代码重构

Python代码重构的艺术与实践 引言 在软件开发过程中&#xff0c;随着项目的不断推进&#xff0c;代码的复杂度通常会逐渐增加。原本简单的程序可能在功能上不断扩展&#xff0c;导致代码的可读性和可维护性下降。此时&#xff0c;代码重构的必要性愈发凸显。本文将从代码重构…