在 C++ 中,std::thread 用于创建和管理线程,但它并不直接支持获取线程的返回结果。为了解决这个问题,我们可以使用 std::packaged_task 来辅助实现。std::packaged_task 是一个可调用对象包装器,它将一个函数封装起来,并可以与 std::future 结合使用来异步获取函数的结果。
使用步骤:
- 封装任务:将需要在线程中执行的函数传给
std::packaged_task。 - 获取 future 对象:通过
std::packaged_task的get_future()方法获得一个std::future对象。 - 启动线程:将
packaged_task移交给std::thread并启动线程。 - 获取结果:通过
future对象的get()方法获取线程执行的返回值。
#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>
int task(int number)
{
std::this_thread::sleep_for(std::chrono::seconds(5));
// 在线程函数内部既可以抛出异常,也可以正常返回结果
//throw std::exception("抛出异常!");
return 100 + number;
}
void test()
{
// 1. 封装任务
std::packaged_task<int(int)> current_task(task);
// 2. 获取 future 对象
std::future<int> result = current_task.get_future();
// 3. 启动线程
// packaged_task 不支持拷贝,只支持移动
// std::move 将 current_task 转换为 右值引用,将其所有权转移给 std::thread
// std::thread 接收到 current_task 的 所有权,并会在内部保存这个对象。
// std::thread t(std::move(current_task), 200);
// std::ref 传递的是 current_task 的 引用,线程内操作的是原始对象。
// std::thread 不会接管 current_task 的生命周期,也不会负责销毁 current_task。
std::thread t(std::ref(current_task), 200);
t.detach();
// 4. 获取结果
// 线程函数可能正确执行返回结果,也可能会抛出异常,需要使用 try 块来处理
try
{
int ret = result.get();
std::cout << "ret = " << ret << std::endl;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
}
int main()
{
test();
return EXIT_SUCCESS;
}
#endif
使用 get 函数获得结果会阻塞当前线程。如果我们不想阻塞在此处,可以使用 wait_for 或者 wait_until 来代替 get 函数。
#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>
int task(int number)
{
std::this_thread::sleep_for(std::chrono::seconds(5));
return 100 + number;
}
void test()
{
std::packaged_task<int(int)> current_task(task);
std::future<int> result = current_task.get_future();
std::thread t(std::move(current_task), 200);
while (true)
{
// 等待指定长度的时间,如果在该时间内子线程没有返回结果,则返回 timeout 状态,否则返回 ready 状态
// std::future_status status = result.wait_for(std::chrono::seconds(1));
std::future_status status = result.wait_until(std::chrono::steady_clock::now() + std::chrono::seconds(1));
if (status == std::future_status::ready)
{
std::cout << "线程结果是:" << result.get() << std::endl;
break;
}
if (status == std::future_status::timeout)
{
std::cout << "任务正在执行中...做点别的事情" << std::endl;
}
}
t.join();
}
int main()
{
test();
return EXIT_SUCCESS;
}
#endif
std::future 只可以获得一次结果,不允许多次获得线程结果。如果需要多次获得线程的结果,可以使用 std::shared_future 来代替 std::future。
#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>
int task(int number)
{
std::this_thread::sleep_for(std::chrono::seconds(5));
return 100 + number;
}
void test()
{
std::packaged_task<int(int)> current_task(task);
#if 0
std::future<int> result = current_task.get_future();
#else
std::shared_future<int> result = current_task.get_future();
#endif
std::thread t(std::move(current_task), 200);
t.join();
result.get();
result.get();
}
int main()
{
test();
return EXIT_SUCCESS;
}
#endif

冀公网安备13050302001966号