当前位置: 首页 > news >正文

windows C++-移除界面工作线程(三)

取消活动任务

Mandelbrot 应用程序创建的 Bitmap 对象的尺寸与客户端窗口大小一致。 每次调整客户端窗口的大小时,应用程序都会创建一个额外的后台任务,为新窗口大小生成一个图像。 应用程序不需要这些中间图像,只需要最终窗口大小的图像。 若要阻止应用程序执行这个额外的工作,可以在 WM_SIZE 和 WM_SIZING 消息的消息处理程序中取消任何活动的绘制任务,然后在调整窗口大小后重新计划绘制工作。

若要在调整窗口大小时取消活动的绘制任务,应用程序将在 WM_SIZING 和 WM_SIZE 消息的处理程序中调用 concurrency::task_group::cancel 方法。 WM_SIZE 消息的处理程序还将调用 concurrency::task_group::wait 方法以等待所有活动的任务完成,然后针对更新后的窗口大小重新计划绘制任务。

在销毁客户端窗口时,最好取消任何活动的绘制任务。 取消任何活动的绘制任务可确保工作线程在客户端窗口销毁后不会将消息发布到 UI 线程。 应用程序将取消 WM_DESTROY 消息的处理程序中的任何活动的绘制任务。

响应取消

执行绘制任务的 CChildView::DrawMandelbrot 方法必须响应取消。 由于运行时使用异常处理来取消任务,因此 CChildView::DrawMandelbrot 方法必须使用异常安全机制来保证正确地清理所有资源。 此示例使用了“资源获取初始化”(RAII) 模式,确保取消任务时位图位已解锁。

在 Mandelbrot 应用程序中添加对取消的支持

代码如下:

// 1. 在 ChildView.h 中,在 CChildView 类的 protected 部分中,
// 为 OnSize、OnSizing 和 OnDestroy 消息映射函数添加声明。
afx_msg void OnPaint();
afx_msg void OnSize(UINT, int, int);
afx_msg void OnSizing(UINT, LPRECT); 
afx_msg void OnDestroy();
DECLARE_MESSAGE_MAP()// 2. 在 ChildView.cpp 中,修改消息映射以包含 WM_SIZE、WM_SIZING 和 
// WM_DESTROY 消息的处理程序。
BEGIN_MESSAGE_MAP(CChildView, CWnd)ON_WM_PAINT()ON_WM_SIZE()ON_WM_SIZING()ON_WM_DESTROY()
END_MESSAGE_MAP()// 3. 实现 CChildView::OnSizing 方法。 此方法将取消任何现有绘制任务。
void CChildView::OnSizing(UINT nSide, LPRECT lpRect)
{// The window size is changing; cancel any existing drawing tasks.m_DrawingTasks.cancel();
}//5. 实现 CChildView::OnSize 方法。 此方法将取消任何现有绘制任务,
// 并为更新后的客户端窗口大小创建新的绘制任务。
void CChildView::OnSize(UINT nType, int cx, int cy)
{// The window size has changed; cancel any existing drawing tasks.m_DrawingTasks.cancel();// Wait for any existing tasks to finish.m_DrawingTasks.wait();// If the new size is non-zero, create a task to draw the Mandelbrot // image on a separate thread.if (cx != 0 && cy != 0){      m_DrawingTasks.run([cx,cy,this]() {DrawMandelbrot(BitmapPtr(new Bitmap(cx, cy)));});}
}// 6. 实现 CChildView::OnDestroy 方法。 此方法将取消任何现有绘制任务。void CChildView::OnDestroy()
{// The window is being destroyed; cancel any existing drawing tasks.m_DrawingTasks.cancel();// Wait for any existing tasks to finish.m_DrawingTasks.wait();
}// 7. 在 ChildView.cpp 中,定义可实现 RAII 模式的 scope_guard 类。
// Implements the Resource Acquisition Is Initialization (RAII) pattern 
// by calling the specified function after leaving scope.
class scope_guard 
{
public:explicit scope_guard(std::function<void()> f): m_f(std::move(f)) { }// Dismisses the action.void dismiss() {m_f = nullptr;}~scope_guard() {// Call the function.if (m_f) {try {m_f();}catch (...) {terminate();}}}private:// The function to call when leaving scope.std::function<void()> m_f;// Hide copy constructor and assignment operator.scope_guard(const scope_guard&);scope_guard& operator=(const scope_guard&);
};// 8. 将以下代码添加到 CChildView::DrawMandelbrot 方法(在对 Bitmap::LockBits 的调用后面):// Create a scope_guard object that unlocks the bitmap bits when it
// leaves scope. This ensures that the bitmap is properly handled
// when the task is canceled.
scope_guard guard([&pBitmap, &bitmapData] {// Unlock the bitmap from system memory.pBitmap->UnlockBits(&bitmapData);      
});// 9. 此代码通过创建 scope_guard 对象来处理取消。 当对象离开作用域时,它会解锁位图位。
// 修改 CChildView::DrawMandelbrot 方法的末尾,以在位图位解锁之后、
// 但在将任何消息发送到 UI 线程之前消除 scope_guard 对象。 
// 这可确保在解锁位图位之前不会更新 UI 线程。
// Unlock the bitmap from system memory.
pBitmap->UnlockBits(&bitmapData);// Dismiss the scope guard because the bitmap has been 
// properly unlocked.
guard.dismiss();// Add the Bitmap object to image queue.
send(m_MandelbrotImages, pBitmap);// Post a paint message to the UI thread.
PostMessage(WM_PAINT);
// Invalidate the client area.
InvalidateRect(NULL, FALSE);// 通过生成并运行应用程序来验证其是否已成功更新。

当你调整窗口大小时,只会对最终窗口大小执行绘制工作。 在销毁窗口时,也会同时取消任何活动的绘制任务。 


http://www.mrgr.cn/news/47553.html

相关文章:

  • 如何打破双亲委派机制
  • 网络安全知识|网安问答题|OSPF报文协议|抓包工具|路由器环路|序列化与反序列化|磁盘利用率|网络攻防
  • 嵌入式数据结构中线性表的具体实现
  • 免费使用Certbot在Amazon EC2上启用https证书
  • 深入浅出理解七层网络协议
  • 【JavaScript】拷贝对象的几种方式与对比
  • 实践体验密集小目标检测,以小麦麦穗颗粒为基准,基于YOLOv9全系列【yolov9/t/s/m/c/e】参数模型开发构建智能精准麦穗颗粒检测计数系统
  • 小猿口算APP脚本(协议版)
  • 毕设---中国移动网站平台管理系统的设计与实现
  • 结合大语言模型的机械臂抓取操作学习
  • 模版进阶 非类型模版参数
  • dayu_widgets-简介
  • [ARC154E] Reverse and Inversion
  • 【TypeScript】知识点梳理(三)
  • Internet Download Manager6.42免费版下载神器新体验
  • redis同步解决 缓存击穿+缓存穿透 原理代码实现
  • 深入理解Transformer的笔记记录(精简版本)---- Transformer
  • MyBatis 数据表与实体映射的隐藏陷阱
  • SAP_FI_表ACDOCA取代的表
  • Python测试框架--Allure