std::thread的使用

一 概述

std::thread 是 C++11 引入的线程库,用于创建和管理多线程程序。

二 基本用法

1 创建线程

#include <iostream>

#include <thread>

// 普通函数作为线程函数

void hello() {

std::cout << "Hello from thread!" << std::endl;

}

// Lambda表达式作为线程函数

auto lambda = \[\]() {

std::cout << "Hello from lambda thread!" << std::endl;

};

// 带参数的函数

void print_number(int num) {

std::cout << "Number: " << num << std::endl;

}

int main() {

// 创建线程

std::thread t1(hello);

std::thread t2(lambda);

std::thread t3(print_number, 42);

// 等待线程完成

t1.join();

t2.join();

t3.join();

return 0;

}

2 类成员函数作为线程函数

#include <iostream>

#include <thread>

class MyClass {

public:

void member_func(int x) {

std::cout << "Member function: " << x << std::endl;

}

static void static_func() {

std::cout << "Static member function" << std::endl;

}

};

int main() {

MyClass obj;

// 调用成员函数

std::thread t1(&MyClass::member_func, &obj, 100);

// 调用静态成员函数

std::thread t2(&MyClass::static_func);

t1.join();

t2.join();

return 0;

}

```

二 线程管理

1 join() 和 detach()

#include <iostream>

#include <thread>

#include <chrono>

void worker() {

std::this_thread::sleep_for(std::chrono::seconds(1));

std::cout << "Worker thread finished" << std::endl;

}

int main() {

std::thread t1(worker);

if (t1.joinable()) {

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

t1.join();

}

std::thread t2(worker);

if (t2.joinable()) {

// detach() - 分离线程(后台运行)

t2.detach();

}

// 注意:分离后不能再 join()

// t2.join(); // 错误!

// 主线程等待,确保分离的线程有机会执行

std::this_thread::sleep_for(std::chrono::seconds(2));

return 0;

}

2 获取线程ID

#include <iostream>

#include <thread>

void print_id() {

std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;

}

int main() {

std::thread t1(print_id);

std::thread t2(print_id);

std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;

std::cout << "t1 ID: " << t1.get_id() << std::endl;

t1.join();

t2.join();

return 0;

}

三 传递参数

1 按值传递

#include <iostream>

#include <thread>

void func(int a, std::string b, double c) {

std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl;

}

int main() {

std::thread t(func, 1, "hello", 3.14);

t.join();

return 0;

}

2 按引用传递

#include <iostream>

#include <thread>

#include <functional> // 需要 std::ref

void modify_value(int& x) {

x = 100;

}

int main() {

int value = 0;

// 使用 std::ref 传递引用

std::thread t(modify_value, std::ref(value));

t.join();

std::cout << "Value after modification: " << value << std::endl; // 输出 100

return 0;

}

3 传递指针

#include <iostream>

#include <thread>

void process_array(int* arr, int size) {

for (int i = 0; i < size; ++i) {

arri *= 2;

}

}

int main() {

int arr\[\] = {1, 2, 3, 4, 5};

std::thread t(process_array, arr, 5);

t.join();

for (int num : arr) {

std::cout << num << " "; // 输出: 2 4 6 8 10

}

std::cout << std::endl;

return 0;

}

四 线程同步

1 使用互斥锁

#include <iostream>

#include <thread>

#include <mutex>

#include <vector>

std::mutex mtx;

int counter = 0;

void increment() {

for (int i = 0; i < 10000; ++i) {

mtx.lock(); // 上锁

++counter;

mtx.unlock(); // 解锁

}

}

int main() {

std::thread t1(increment);

std::thread t2(increment);

t1.join();

t2.join();

std::cout << "Counter value: " << counter << std::endl; // 应该是 20000

return 0;

}

2 使用 RAII 风格的锁

#include <iostream>

#include <thread>

#include <mutex>

std::mutex mtx;

int counter = 0;

void increment() {

for (int i = 0; i < 10000; ++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 << "Counter value: " << counter << std::endl;

return 0;

}

五 线程移动

#include <iostream>

#include <thread>

#include <vector>

void worker(int id) {

std::cout << "Worker " << id << " started" << std::endl;

}

int main() {

// 线程对象不能复制,只能移动

std::thread t(worker, 1);

// 移动语义

std::thread t2 = std::move(t);

// t 现在为空,不能再使用

// t.join(); // 错误!

if (t2.joinable()) {

t2.join();

}

// 线程向量

std::vector<std::thread> threads;

for (int i = 0; i < 5; ++i) {

// 使用 emplace_back 直接构造

threads.emplace_back(worker, i);

}

// 等待所有线程完成

for (auto& t : threads) {

if (t.joinable()) {

t.join();

}

}

return 0;

}

六 实用技巧

1 使用 packaged_task

#include <iostream>

#include <thread>

#include <future>

#include <functional>

int compute(int x, int y) {

return x * y;

}

int main() {

std::packaged_task<int(int, int)> task(compute);

std::future<int> result = task.get_future();

// 在新线程中执行任务

std::thread t(std::move(task), 6, 7);

// 获取结果

std::cout << "Result: " << result.get() << std::endl;

t.join();

return 0;

}

2 线程睡眠

#include <iostream>

#include <thread>

#include <chrono>

void slow_worker() {

std::cout << "Worker starting..." << std::endl;

// 睡眠 2 秒

std::this_thread::sleep_for(std::chrono::seconds(2));

std::cout << "Worker finished!" << std::endl;

}

int main() {

std::thread t(slow_worker);

t.join();

return 0;

}

七 注意事项

1 资源管理:确保线程在析构前被 join() 或 detach()。

2 数据竞争:使用适当的同步机制。

3 异常安全:线程函数中的异常需要处理。

4 性能考虑:避免创建过多线程。

5 平台差异:线程行为在不同操作系统上可能略有不同。

八 完整示例

#include <iostream>

#include <thread>

#include <vector>

#include <mutex>

#include <chrono>

class ThreadPool {

private:

std::vector<std::thread> workers;

std::mutex mtx;

public:

void add_worker(int id) {

workers.emplace_back(this, id() {

{

std::lock_guard<std::mutex> lock(mtx);

std::cout << "Worker " << id << " started" << std::endl;

}

std::this_thread::sleep_for(std::chrono::milliseconds(100));

{

std::lock_guard<std::mutex> lock(mtx);

std::cout << "Worker " << id << " finished" << std::endl;

}

});

}

void wait_all() {

for (auto& t : workers) {

if (t.joinable()) {

t.join();

}

}

}

};

int main() {

ThreadPool pool;

// 创建 10 个工作线程

for (int i = 0; i < 10; ++i) {

pool.add_worker(i);

}

// 等待所有线程完成

pool.wait_all();

std::cout << "All workers finished!" << std::endl;

return 0;

}

这个示例展示了 std::thread 的主要用法。实际使用时,建议考虑使用更高级的抽象,如 C++17 的 std::jthread 或第三方线程池库。

相关推荐
StarRocks_labs35 分钟前
StarRocks 接入 Paimon C++:让湖上查询进入原生执行链路
starrocks·c++·sql·jni·paimon·auto·湖上查询
垆边人似月.43 分钟前
华为题:字符串中最长连续数字串
开发语言·c++·算法
罗湖老棍子1 小时前
座位安排(洛谷-P2071)
c++·算法·图论·匈牙利算法·二分图匹配
IOT那些事儿1 小时前
C++17和20版本差异
c++·mingw·msvc
垆边人似月.1 小时前
华为题:任务调度
数据结构·c++·算法
局部有解1 小时前
Leetcode - 42 接雨水(一维)
数据结构·c++·算法·leetcode
fpcc2 小时前
c++20新功能—std::osyncstream
c++·c++20
H.莓飛2 小时前
【C++】模板初阶
linux·开发语言·c++·visual studio
十五年专注C++开发2 小时前
基于Asio2实现http服务器的实践总结(二)
服务器·c++·http·asio2
技术不好的崎鸣同学2 小时前
第七章:模块踩踏以覆写导出函数绕过CFG
c++·windows·安全·系统安全