c++ 多线程
一、基本概念
全局函数可以作为std::thread的构造函数参数,创建新线程时会自动调用该函数。
- 函数可以是普通函数、静态函数、lambda表达式
- 线程启动时立即执行该函数
- 函数执行完毕,线程自动结束
二、基本用法
示例1:最简单的全局函数
cpp
#include <iostream>
#include <thread>
#include <chrono>
// 全局函数定义
void simpleTask() {
std::cout << "线程ID: " << std::this_thread::get_id()
<< " 正在执行简单任务" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "任务完成" << std::endl;
}
int main() {
std::cout << "主线程ID: " << std::this_thread::get_id() << std::endl;
// 创建线程,传入全局函数指针
std::thread t(simpleTask);
// 等待线程完成
t.join();
return 0;
}
三、带参数的全局函数
示例2:传递参数给线程函数
cpp
#include <iostream>
#include <thread>
#include <string>
// 带参数的全局函数
void printMessage(const std::string& message, int count) {
for (int i = 0; i < count; ++i) {
std::cout << "消息[" << i << "]: " << message
<< " (线程ID: " << std::this_thread::get_id() << ")"
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
// 创建线程时传递参数
std::thread t1(printMessage, "Hello, Thread!", 3);
std::thread t2(printMessage, "另一个线程", 5);
t1.join();
t2.join();
return 0;
}
四、不同类型的全局函数
示例3:静态函数
cpp
#include <iostream>
#include <thread>
class MyClass {
public:
static void staticTask(int value) {
std::cout << "静态函数,值: " << value
<< " 线程ID: " << std::this_thread::get_id()
<< std::endl;
}
};
// 普通全局函数
void globalTask(const char* name) {
std::cout << "全局函数: " << name << std::endl;
}
int main() {
// 使用静态函数作为线程入口
std::thread t1(MyClass::staticTask, 42);
// 使用普通全局函数
std::thread t2(globalTask, "测试线程");
// 使用函数指针
void (*funcPtr)(const char*) = globalTask;
std::thread t3(funcPtr, "函数指针");
t1.join();
t2.join();
t3.join();
return 0;
}
五、传递引用和指针参数
示例4:传递引用参数
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
// 修改共享数据的全局函数
void processVector(std::vector<int>& vec, int multiplier) {
std::cout << "处理向量,大小: " << vec.size()
<< " 线程ID: " << std::this_thread::get_id()
<< std::endl;
// 修改向量元素
for (auto& num : vec) {
num *= multiplier;
}
}
// 传递指针
void processArray(int* arr, int size) {
std::cout << "处理数组,大小: " << size << std::endl;
for (int i = 0; i < size; ++i) {
arr[i] += 10;
}
}
int main() {
// 示例1:传递引用(需要使用std::ref包装)
std::vector<int> data = {1, 2, 3, 4, 5};
std::thread t1(processVector, std::ref(data), 2);
t1.join();
std::cout << "处理后的向量: ";
for (int num : data) {
std::cout << num << " ";
}
std::cout << std::endl;
// 示例2:传递指针
int array[5] = {10, 20, 30, 40, 50};
std::thread t2(processArray, array, 5);
t2.join();
std::cout << "处理后的数组: ";
for (int i = 0; i < 5; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
六、返回值的处理
示例5:使用future获取返回值
cpp
#include <iostream>
#include <thread>
#include <future>
#include <numeric>
#include <vector>
// 计算向量和的全局函数
int calculateSum(const std::vector<int>& vec) {
std::cout << "计算线程ID: " << std::this_thread::get_id() << std::endl;
// 模拟耗时计算
std::this_thread::sleep_for(std::chrono::seconds(1));
int sum = std::accumulate(vec.begin(), vec.end(), 0);
return sum;
}
// 返回多个值的函数
std::pair<int, double> calculateStats(const std::vector<int>& vec) {
if (vec.empty()) return {0, 0.0};
int sum = std::accumulate(vec.begin(), vec.end(), 0);
double avg = static_cast<double>(sum) / vec.size();
return {sum, avg};
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 方式1:使用std::async(内部使用线程)
std::future<int> future1 = std::async(std::launch::async, calculateSum, numbers);
// 方式2:使用packaged_task
std::packaged_task<int(const std::vector<int>&)> task(calculateSum);
std::future<int> future2 = task.get_future();
std::thread t(std::move(task), numbers);
// 获取结果
std::cout << "Async结果: " << future1.get() << std::endl;
std::cout << "Thread结果: " << future2.get() << std::endl;
t.join();
// 获取多个返回值
std::packaged_task<std::pair<int, double>(const std::vector<int>&)>
statsTask(calculateStats);
std::future<std::pair<int, double>> statsFuture = statsTask.get_future();
std::thread statsThread(std::move(statsTask), numbers);
auto [sum, avg] = statsFuture.get();
std::cout << "\n统计结果:\n";
std::cout << "总和: " << sum << "\n平均值: " << avg << std::endl;
statsThread.join();
return 0;
}
七、注意事项
关键注意事项
cpp
#include <iostream>
#include <thread>
// 1. 线程参数是值传递(除非使用std::ref)
void demonstratePassing(int value, int& ref, const std::string& str) {
value += 10; // 修改的是副本
ref += 10; // 修改的是原始引用
std::cout << "字符串: " << str << std::endl;
}
int main() {
int a = 5;
int b = 10;
std::string msg = "测试";
// 正确传递引用
std::thread t(demonstratePassing, a, std::ref(b), msg);
t.join();
std::cout << "a = " << a << std::endl; // 仍然是5
std::cout << "b = " << b << std::endl; // 变为20
// 2. 确保参数生命周期
{
int* ptr = new int(42);
std::thread t2([](int* p) {
std::cout << "值: " << *p << std::endl;
delete p; // 在线程内清理
}, ptr);
t2.detach();
}
// 3. 异常安全处理
try {
std::thread t3([]() {
throw std::runtime_error("线程内部异常");
});
// 确保线程在异常发生时也能被join
t3.join();
} catch (const std::exception& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
}
return 0;
}
选择建议
- 简单任务 → 全局函数
- 需要状态管理 → 函数对象或成员函数
- 一次性使用 → lambda表达式
- 需要返回值 → 使用std::future