跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C++ packaged tas
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{DISPLAYTITLE:C++ packaged_task}} '''C++ packaged_task''' 是 C++11 标准引入的一个高级多线程工具,它允许将可调用对象(如函数、Lambda表达式或函数对象)与一个[[future (C++)|future]]对象关联起来,从而在异步任务完成后获取结果。`packaged_task` 提供了一种便捷的方式将任务的执行与结果的获取分离,常用于线程池、任务队列等场景。 == 概述 == `std::packaged_task` 是一个类模板,其模板参数为函数签名(例如 `int(int, int)`)。它封装了一个可调用对象,并允许通过关联的 `std::future` 对象获取该任务的返回值。其主要特点包括: * 将任务(函数)的执行与结果的存储绑定。 * 通过 `get_future()` 方法获取一个 `future` 对象,用于异步获取结果。 * 任务可以通过调用 `operator()` 直接执行,或传递给线程执行。 == 基本用法 == 以下是一个简单的示例,展示 `packaged_task` 的基本用法: <syntaxhighlight lang="cpp"> #include <iostream> #include <future> #include <thread> int add(int a, int b) { return a + b; } int main() { // 创建一个 packaged_task,封装 add 函数 std::packaged_task<int(int, int)> task(add); // 获取与任务关联的 future std::future<int> result = task.get_future(); // 将任务移动到线程中执行 std::thread t(std::move(task), 2, 3); // 等待结果并输出 std::cout << "Result: " << result.get() << std::endl; t.join(); return 0; } </syntaxhighlight> '''输出:''' <pre> Result: 5 </pre> '''代码解释:''' 1. 创建一个 `packaged_task` 对象 `task`,封装了 `add` 函数。 2. 调用 `task.get_future()` 获取关联的 `future` 对象 `result`。 3. 将 `task` 移动到线程 `t` 中执行,并传递参数 `2` 和 `3`。 4. 主线程通过 `result.get()` 阻塞等待结果并输出。 == 与 Lambda 表达式结合 == `packaged_task` 可以与 Lambda 表达式结合,实现更灵活的任务定义: <syntaxhighlight lang="cpp"> #include <iostream> #include <future> #include <thread> int main() { // 创建一个 packaged_task,封装 Lambda 表达式 std::packaged_task<int()> task([]() { return 42; }); // 获取 future std::future<int> result = task.get_future(); // 直接执行任务(也可以传递给线程) task(); // 输出结果 std::cout << "The answer is: " << result.get() << std::endl; return 0; } </syntaxhighlight> '''输出:''' <pre> The answer is: 42 </pre> == 实际应用场景 == `packaged_task` 常用于以下场景: 1. '''线程池''':将任务封装为 `packaged_task` 并提交到线程池,通过 `future` 获取结果。 2. '''异步任务链''':将多个任务串联,前一个任务的输出作为后一个任务的输入。 3. '''延迟计算''':在需要时才启动任务执行。 === 线程池示例 === 以下是一个简化的线程池实现片段,展示 `packaged_task` 的典型用法: <syntaxhighlight lang="cpp"> #include <iostream> #include <future> #include <queue> #include <thread> #include <mutex> #include <condition_variable> class ThreadPool { public: ThreadPool(size_t num_threads) { for (size_t i = 0; i < num_threads; ++i) { workers.emplace_back([this] { while (true) { std::packaged_task<void()> task; { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock, [this] { return !tasks.empty() || stop; }); if (stop && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } task(); } }); } } template <typename F> auto enqueue(F&& f) -> std::future<decltype(f())> { using return_type = decltype(f()); auto task = std::packaged_task<return_type()>(std::forward<F>(f)); auto res = task.get_future(); { std::unique_lock<std::mutex> lock(queue_mutex); tasks.emplace(std::move(task)); } condition.notify_one(); return res; } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for (auto& worker : workers) { worker.join(); } } private: std::vector<std::thread> workers; std::queue<std::packaged_task<void()>> tasks; std::mutex queue_mutex; std::condition_variable condition; bool stop = false; }; int main() { ThreadPool pool(4); auto result = pool.enqueue([]() { return "Hello from thread pool!"; }); std::cout << result.get() << std::endl; return 0; } </syntaxhighlight> '''输出:''' <pre> Hello from thread pool! </pre> == 与 std::async 的比较 == `packaged_task` 和 `std::async` 都可用于异步执行任务,但有以下区别: {| class="wikitable" |- ! 特性 !! `packaged_task` !! `std::async` |- | 控制权 | 完全控制任务的启动方式 | 由系统决定是否启动新线程 |- | 灵活性 | 更高,可手动管理线程 | 较低,但更简单 |- | 适用场景 | 需要精细控制任务执行时 | 快速实现异步调用时 |} == 状态与异常处理 == * 如果任务抛出异常,异常会被存储在 `future` 中,并在调用 `get()` 时重新抛出。 * `packaged_task` 只能被移动(move),不能被复制。 === 异常处理示例 === <syntaxhighlight lang="cpp"> #include <iostream> #include <future> #include <thread> void might_throw(bool do_throw) { if (do_throw) { throw std::runtime_error("Exception from task!"); } std::cout << "Task completed normally." << std::endl; } int main() { std::packaged_task<void(bool)> task(might_throw); auto future = task.get_future(); std::thread t(std::move(task), true); t.join(); try { future.get(); } catch (const std::exception& e) { std::cerr << "Caught exception: " << e.what() << std::endl; } return 0; } </syntaxhighlight> '''输出:''' <pre> Caught exception: Exception from task! </pre> == 总结 == * `packaged_task` 是一个强大的工具,用于将任务与结果分离。 * 它提供了对任务执行的精细控制,适用于需要手动管理线程的场景。 * 通过 `future` 可以安全地获取结果或异常。 {{C++多线程导航}} [[Category:编程语言]] [[Category:C++]] [[Category:C++ 多线程]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
该页面使用的模板:
模板:C++多线程导航
(
编辑
)