当前位置: 首页 > news >正文

c++多线程(1)------创建和管理线程td::thread

  • 操作系统:ubuntu22.04
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

std::thread 是 C++11 标准库中用于创建和管理线程的核心类,定义在 头文件中。它使得多线程编程变得简单、类型安全且跨平台。

一、std::thread 简介

std::thread 是一个类,代表一个执行线程。你可以用它来启动一个函数(普通函数、lambda、函数对象、成员函数等)在新的线程中运行。
🔧 所需头文件:

#include <thread>

📦 常用成员函数:

函数说明
join()等待线程执行完毕(阻塞主线程)
detach()分离线程,让其在后台独立运行
get_id()获取线程的唯一 ID
joinable()判断线程是否可以 join 或 detach
swap()交换两个 thread 对象
native_handle()获取底层平台的原生线程句柄(如 pthread_t)

二、创建线程的多种方式(附示例)

  1. 使用普通函数
#include <iostream>
#include <thread>
#include <chrono>void hello() 
{std::this_thread::sleep_for(std::chrono::milliseconds(100));std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(hello);  // 启动线程执行 hello 函数std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join();  // 等待线程结束std::cout << "Thread joined." << std::endl;return 0;
}

输出示例:

Main thread ID: 1
Hello from thread 2
Thread joined.
  1. 使用带参数的函数
void print_message(const std::string& msg, int n) 
{for (int i = 0; i < n; ++i) {std::cout << msg << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(50));}
}int main()
{std::thread t(print_message, "Hello from thread!", 3);std::cout << "Main thread is running..." << std::endl;t.join();std::cout << "Thread finished." << std::endl;return 0;
}
⚠️ 注意:参数是值传递的。如果要传引用,必须用 std::ref。

✅ 正确传递引用:

void increment(int& x)
{++x;
}int main() 
{int a = 0;std::thread t(increment, std::ref(a));  // 使用 std::ref 传引用t.join();std::cout << "a = " << a << std::endl;  // 输出: a = 1return 0;
}

✅ 3. 使用 Lambda 表达式

int main()
{int local = 10;std::thread t([local](){  // 捕获 local 的副本std::cout << "Lambda: local = " << local << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));});t.join();return 0;
}
提示:如果要修改捕获的变量,使用 mutable 或传引用:
std::thread t([&local]() mutable 
{local += 5;std::cout << "Modified: " << local << std::endl;
});

✅ 4. 使用函数对象(仿函数)

struct Task 
{void operator()() const{std::cout << "Task executed in thread " << std::this_thread::get_id() << std::endl;}
};int main() 
{std::thread t(Task{});t.join();return 0;
}

✅ 5. 使用类的成员函数

class Worker 
{
public:void work(int id){std::cout << "Worker " << id << " working in thread " << std::this_thread::get_id() << std::endl;}
};int main() 
{Worker w;std::thread t(&Worker::work, &w, 42);  // &w 是对象指针,42 是参数t.join();return 0;
}

🔍 解释:&Worker::work 是成员函数指针,&w 是对象地址,42 是参数。

三、join() vs detach()

❗ 每个 std::thread 对象在析构前必须被 join 或 detach,否则程序会 std::terminate()。
✅ join():等待线程结束

std::thread t(some_function);
t.join();  // 主线程阻塞,直到 t 结束
// 此时 t 不再可 join,t.joinable() 返回 false

✅ detach():分离线程

std::thread t(some_function);
t.detach();  // 线程在后台运行,不再与 thread 对象关联
// 不能再 join,线程生命周期由系统管理
⚠️ 分离线程的风险:如果主线程结束,整个程序终止,分离线程也会被强制终止。

🧪 四、检查线程状态:joinable()

std::thread t(some_function);if (t.joinable()) 
{t.join();  // 安全调用
}
常用于异常安全代码中,确保线程被正确处理。

🧰 五、线程 ID 与当前线程操作

#include <iostream>
#include <thread>void show_id() 
{std::cout << "This thread ID: " << std::this_thread::get_id() << std::endl;
}int main() 
{std::thread t(show_id);std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join();// 让出 CPU 时间片std::this_thread::yield();// 休眠 500 毫秒std::this_thread::sleep_for(std::chrono::milliseconds(500));return 0;
}

🧱 六、线程安全与共享数据(简单示例)

#include <iostream>
#include <thread>
#include <mutex>int counter = 0;
std::mutex mtx;void increment() 
{for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(mtx);++counter;}
}int main() 
{std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter: " << counter << std::endl;  // 应为 200000return 0;
}
🔐 使用 std::mutex 和 std::lock_guard 保护共享变量 counter。

🚫 七、常见错误与注意事项

❌ 错误1:未调用 join 或 detach

int main()
{std::thread t([]{ std::cout << "Hello"; });return 0;  // t 析构时未 join/detach → 调用 std::terminate()
}

✅ 正确做法:

std::thread t(...);
// ...
t.join();  // 或 t.detach();

❌ 错误2:传递指针或引用时对象已销毁

std::thread t(increment, std::ref(local_var));
// 如果 local_var 是局部变量且线程未结束,可能访问已销毁内存
✅ 建议:确保线程使用的数据生命周期长于线程本身。

✅ 八、完整示例:多线程并行计算

#include <iostream>
#include <vector>
#include <thread>
#include <numeric>void accumulate(const std::vector<int>& vec, int start, int end, int& result){result = std::accumulate(vec.begin() + start, vec.begin() + end, 0);
}int main() 
{std::vector<int> data(100000, 1);  // 10万个1int sum1 = 0, sum2 = 0;std::thread t1(accumulate, std::ref(data), 0, 50000, std::ref(sum1));std::thread t2(accumulate, std::ref(data), 50000, 100000, std::ref(sum2));t1.join();t2.join();std::cout << "Total sum: " << sum1 + sum2 << std::endl;  // 100000return 0;
}

总结:std::thread 核心要点

要点说明
✅ 启动线程std::thread t(func, args…)
✅ 等待结束t.join()
✅ 后台运行t.detach()
✅ 安全检查t.joinable()
✅ 线程IDt.get_id() 或 std::this_thread::get_id()
✅ 传引用使用 std::ref()
✅ 异常安全在异常路径中也要 join/detach

掌握 std::thread 是学习 C++ 多线程的第一步。结合 mutex、condition_variable 和 future,你就能构建出高效、安全的并发程序。建议多写小例子练习传参、生命周期管理、同步等关键点。

http://www.dtcms.com/a/366018.html

相关文章:

  • Python数据分析与处理(二):将数据写回.mat文件的不同方法【超详细】
  • AI+法律:用ERNIE-Bot解析合同条款,识别风险点
  • 进程管理和IPC
  • 常用假设检验方法及 Python 实现
  • 多层环境室内定位系统综述总结
  • 【JavaEE】(22) Spring 事务
  • 苏哒智能会议一体机:让会议管理进入智能时代
  • Java与Vue构建的企业设备资产管理系统,集成后台管理与移动端操作,覆盖设备全生命周期,支持采购、维护、报废等流程,提供完整源码,助力企业高效管控资产
  • 刻意练习实践说明使用手册
  • nginx配置讲解
  • GitLens:VS Code下高效解决代码追溯的Git管理实用插件
  • Spring Boot + Nacos 配置中心示例工程
  • ego(2)---初始轨迹生成后的关键点采样
  • 一文读懂线性回归的灵魂:成本函数 J(w,b) 全解析
  • K8s基于节点软亲和的高 CPU Pod 扩容与优先调度方案
  • 华为OD最新机试真题-二进制差异数-OD统一考试(C卷)
  • 《K8s网络策略与CNI插件交互问题分析:基于真实案例的排查方法》
  • 卷积操作原来分3种
  • (二)文件管理-基础命令-mkdir命令的使用
  • C++CSP-J/S必背模板
  • Estimating the Number of Sources: An Efficient Maximization Approach
  • 上下文记忆力媲美Genie3,且问世更早:港大和可灵提出场景一致的交互式视频世界模型!
  • Guidelines for using Adaptive Platform interfaces
  • redisson功能完整指南
  • 【OpenGL】LearnOpenGL学习笔记19 - 几何着色器 Geometry Shader
  • 【机器学习深度学习】RAG边界处理策略
  • Vision Pro图像处理工具全解析
  • ClickHouse使用Docker部署
  • 刷新记录:TapData Oracle 日志同步性能达 80K TPS,重塑实时同步新标准
  • mysy2使用