在现代C++中,标准库提供了std::async和std::future来简化异步编程。与传统的线程管理方式相比,它们可以让我们更专注于业务逻辑,而不必关心线程的创建、同步和资源释放。下面我们从基础用法、异常处理、任务取消、线程池模拟以及性能对比等角度,系统阐述如何在实际项目中高效地使用这两者。
1. 基础用法
#include <future>
#include <iostream>
int compute(int a, int b) {
std::this_thread::sleep_for(std::chrono::seconds(2));
return a + b;
}
int main() {
std::future <int> fut = std::async(std::launch::async, compute, 5, 7);
std::cout << "主线程继续执行...\n";
int result = fut.get(); // 阻塞等待结果
std::cout << "结果: " << result << '\n';
}
std::launch::async保证函数在新线程中立即执行。
std::launch::deferred则会把任务延迟到get()或wait()时再执行。
- 若省略第二个参数,编译器会根据
std::launch::async | std::launch::deferred默认策略决定。
2. 异常与错误传播
当异步任务内部抛出异常时,std::future::get()会重新抛出同一异常,供调用方捕获。
int errorProne(int n) {
if (n == 0) throw std::runtime_error("除零错误");
return 10 / n;
}
int main() {
auto f = std::async(std::launch::async, errorProne, 0);
try {
f.get();
} catch (const std::exception& e) {
std::cerr << "捕获异常: " << e.what() << '\n';
}
}
3. 任务取消与超时
std::future本身不支持取消,但可以通过共享状态或标志配合实现。最常见的做法是使用`std::atomic
`或`std::condition_variable`,让任务定期检查是否应提前退出。
“`cpp
#include
#include
std::atomic
cancelFlag(false);
void longTask() {
for (int i = 0; i fut = std::async(std::launch::async, longTask);
std::this_thread::sleep_for(std::chrono::seconds(3));
cancelFlag.store(true);
fut.wait(); // 等待线程结束
}
“`
若需超时,可在主线程使用`future::wait_for`或`future::wait_until`:
“`cpp
if (fut.wait_for(std::chrono::seconds(5)) == std::future_status::timeout) {
std::cout
#include
#include
#include
#include
#include
class ThreadPool {
public:
ThreadPool(size_t threads);
~ThreadPool();
template
auto enqueue(F&& f, Args&&… args)
-> std::future>;
private:
std::vector workers;
std::queue> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
ThreadPool::ThreadPool(size_t threads) : stop(false) {
for(size_t i=0;i task;
{
std::unique_lock lock(this->queue_mutex);
this->condition.wait(lock, [this]{return this->stop || !this->tasks.empty();});
if(this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
ThreadPool::~ThreadPool() {
{
std::unique_lock lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(std::thread &worker: workers)
worker.join();
}
template
auto ThreadPool::enqueue(F&& f, Args&&… args)
-> std::future> {
using return_type = typename std::invoke_result_t;
auto task = std::make_shared>(
std::bind(std::forward
(f), std::forward(args)…));
std::future
res = task->get_future();
{
std::unique_lock lock(queue_mutex);
if(stop) throw std::runtime_error(“enqueue on stopped ThreadPool”);
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
“`
### 5. 性能考量
– **任务粒度**:若任务非常短小(