尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++线程异步和wpf中比较

C++线程异步和wpf中比较 概念理解C线程异步任务协程 (C20 Coroutines) —— “真正的 async/await”回到 WPF 的 awaitC在使用wpf中发现一个很方便的使用我在下发任务时直接使用async 标记一个异步方法在这个异步方法里面使用await去执行一个比较耗时的方法完全不卡界面而且该耗时方法在执行完成切到当前函数然后继续进行觉得使用起来很简单和C进行比对如下深入理解一下相关概念线程真·并行它真的在多核 CPU 的另一个核心上跑。手动管理你必须决定是 join()主线程停下来等它结束还是 detach()让它自己跑主线程不管了类似“后台守护线程”。无返回值函数跑完了结果怎么拿你得自己通过引用参数、全局变量或者配合 std::promise 来传值。风险大如果主线程结束了而子线程没 join 也没 detach程序会直接崩溃 (std::terminate)。#includeiostream#includethread#includechronovoidheavyTask(){std::this_thread::sleep_for(std::chrono::seconds(2));std::cout子线程任务完成std::endl;}intmain(){std::cout主线程开始std::endl;// 1. 创建并启动线程std::threadt(heavyTask);// 2. 必须决定命运// t.join(); // 主线程在这里阻塞等待直到 t 跑完同步效果t.detach();// 主线程继续跑t 在后台自己跑异步效果但无法获取返回值std::cout主线程继续做别的事...std::endl;// 注意如果 main 结束detach 的线程可能会被强制杀死需小心处理生命周期std::this_thread::sleep_for(std::chrono::seconds(3));return0;}异步任务C11 引入了更高级的抽象。你不再直接管理线程而是提交一个“任务”系统决定是开新线程跑还是稍微晚点跑。含义std::async启动一个异步任务返回一个 std::future。std::future一个“未来对象”代表还没出来的结果。你可以用它来等待结果或获取结果。特点自动管理不需要手动 joinfuture 析构时会自动等待除非你特意分离。有返回值直接 f.get() 就能拿到函数返回值。线程池策略默认情况下std::launch::async | std::launch::deferred标准库实现可能会复用线程池不一定每次都新开线程取决于具体编译器实现#includeiostream#includefuture#includechrono#includethreadintheavyTask(){std::this_thread::sleep_for(std::chrono::seconds(2));return42;// 返回结果}intmain(){std::cout主线程提交任务std::endl;// 1. 启动异步任务 (std::launch::async 强制新开线程)std::futureintresultstd::async(std::launch::async,heavyTask);std::cout主线程任务已提交正在做别的事...std::endl;// ... 做一些其他事 ...// 2. 获取结果 (如果任务没做完这里会阻塞等待)std::cout主线程等待结果...std::endl;intvalueresult.get();// 拿到返回值 42std::cout主线程结果是 valuestd::endl;return0;}类比你把任务包给快递公司std::async给你一个单号std::future。你可以先去忙别的想查结果时凭单号去取.get()如果货没到你就得在柜台等着。std::async和std::future启动是异步的但获取结果是同步的阻塞的最大的意义在于把“等待的时间”利用起来// 1. 提交任务后台开始做菜autoresultstd::async(heavyTask);// 2. 【关键】在等待菜做好的这 2 秒里主线程可以去干别的事doSomethingElse();// 假设这也需要 1 秒。此时后台也在做菜。// 3. 等到需要做结果的时候再去取// 如果 doSomethingElse() 花了 1 秒而做菜要 2 秒。// 此时调用 get()只需要再等 1 秒 (2-11)。// 如果 doSomethingElse() 花了 3 秒此时菜早好了get() 瞬间返回不用等。intvalueresult.get();总耗时Max(2 秒做菜1 秒做别的) 剩余等待 约 2 秒多一点。体验界面流畅因为耗时的 doSomethingElse 和后台计算重叠执行了。协程 (C20 Coroutines) —— “真正的 async/await”这是 C20 引入的革命性特性终于有了类似 C# 的 co_await。含义函数可以暂停和恢复而不阻塞线程。巨大差异重要C# 的 async/await是开箱即用的。编译器帮你生成状态机标准库提供了 Task你直接用就行。C20 的 co_await只是底层机制语法关键字。标准库没有提供现成的 Task 类或调度器这意味着你想在 C20 里用协程通常需要自己写一个 Task 类或者使用第三方库如 cppcoro, Boost.ASIO, libunifex。这就像给了你发动机零件但没给你整车你得自己组装或者找别人组装好的车。// 伪代码示例 (需要配合 cppcoro 等库才能编译运行)#includecppcoro/task.hpp#includecppcoro/sleep.hpp// 这是一个协程函数taskintmyAsyncFunction(){autoresultstd::async(heavyTask);// co_await 的神奇之处// 如果任务没好它会【挂起】当前函数把控制权交还给调用者比如 UI 消息循环。// 它不会阻塞线程// 等任务好了系统会自动【恢复】这个函数继续往下执行。intvalueco_awaitresult;updateUI(value);// 这里拿到值时界面一直是流畅的}回到 WPF 的 await/// summary/// 模拟耗时操作并返回一个整数结果/// /summary/// param namemilliseconds等待时间/param/// returns等待结束后的计数值/returnsprivateasync TaskintGetSnapshotAfterDelayAsync(intmilliseconds){// 1. 先异步等待 (不阻塞界面)await Task.Delay(milliseconds);// 2. 等待结束后执行逻辑 (比如加锁读取数据)intresultValue;lock(_lockObj){resultValue_sharedCounter;}// 3. 返回结果// 注意虽然返回类型是 Taskint但你这里直接 return int 即可// 编译器会自动把它包装成 TaskintreturnresultValue;}privateasyncvoidBtnCheck_Click(object sender,RoutedEventArgs e){btnCheck.IsEnabledfalse;lblStatus.Text状态正在执行带返回值的异步任务...;lblSnapshot.Text正在等待并计算...;// 关键点await 之后得到的直接就是 int 类型的值// 就像调用普通同步方法一样自然intfinalValueawaitGetSnapshotAfterDelayAsync(2000);// 代码执行到这里说明 2 秒已过且拿到了返回值lblSnapshot.Text$异步读取结果: {finalValue};lblStatus.Text$状态任务完成。最终返回值是 {finalValue};btnCheck.IsEnabledtrue;}这里和协程很像都是任务丢出去切回调用者线程等任务执行完成继续往后执行后续代码 而在20以前我如果需要拿值 int value result.get(); 这时候都是阻塞的。而20之后可以等那边执行完成之后自动返回执行后续流程真正的异步
返回列表