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

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

本文档演示了如何使用并发运行时将 Microsoft 基础类 (MFC) 应用程序中由用户界面 (UI) 线程执行的工作移动到工作线程。 本文档还演示了如何提高冗长绘制操作的性能。

通过将阻塞性操作(例如,绘制)卸载到工作线程来从 UI 线程中移除工作,可以提高应用程序的响应能力。本文使用可生成 Mandelbrot 分形的绘制例程来演示一个冗长的阻塞性操作。 Mandelbrot 分形的生成也非常适合并行化,因为每个像素的计算都是独立于所有其他计算的。

创建 Visual C++ MFC 应用程序

使用“MFC 应用程序向导”创建具有所有默认设置的 MFC 应用程序。 有关如何为 Visual Studio 版本打开向导的说明,请参阅演练:使用新的 MFC Shell 控件。

为项目键入一个名称,例如 Mandelbrot,然后单击“确定”以显示“MFC 应用程序向导”。

在“应用程序类型”窗格中,选择“单个文档”。 确保清除“文档/视图体系结构支持”复选框。

单击“完成”以创建项目并关闭“MFC 应用程序向导”。

通过生成并运行应用程序来验证其是否已成功创建。 若要生成应用程序,请在“生成”菜单上单击“生成解决方案”。 如果应用程序已成功生成,请单击“调试”菜单上的“开始调试”来运行应用程序。

实现 Mandelbrot 应用程序的串行版本

本部分介绍了如何绘制 Mandelbrot 分形。 此版本将 Mandelbrot 分形绘制到 GDI+ 位图对象,然后将该位图的内容复制到客户端窗口。下面的代码实现 Mandelbrot 应用程序的串行版本:

// 1.在 pch.h(在 Visual Studio 2017 及更早版本中为 stdafx.h)中,添加以下 #include 指令:

#include <memory>

// 2. 在 ChildView.h 中,在 pragma 指令后面定义 BitmapPtr 类型。 
// BitmapPtr 类型允许使用一个指向要由多个组件共享的 Bitmap 对象的指针。 
// 当任何组件都不再引用 Bitmap 对象时,该对象将被删除。

typedef std::shared_ptr<Gdiplus::Bitmap> BitmapPtr;

// 3. 在 ChildView.h 中,将以下代码添加到 CChildView 类的 protected 部分:

protected:
   // Draws the Mandelbrot fractal to the specified Bitmap object.
   void DrawMandelbrot(BitmapPtr);

protected:
   ULONG_PTR m_gdiplusToken;

// 4. 在 ChildView.cpp 中,注释掉或移除以下行。
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#endif

// 5. 在调试内部版本中,此步骤将阻止应用程序使用与 GDI+ 不兼容的 DEBUG_NEW 分配器。
// 在 ChildView.cpp 中,向 Gdiplus 命名空间添加一个 using 指令。
using namespace Gdiplus;

// 6. 将以下代码添加到 CChildView 类的构造函数和析构函数,以初始化和关闭 GDI+。

CChildView::CChildView()
{
   // Initialize GDI+.
   GdiplusStartupInput gdiplusStartupInput;
   GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
}

CChildView::~CChildView()
{
   // Shutdown GDI+.
   GdiplusShutdown(m_gdiplusToken);
}

// 7. 实现 CChildView::DrawMandelbrot 方法。 
// 此方法会将 Mandelbrot 分形绘制到指定的 Bitmap 对象。
// Draws the Mandelbrot fractal to the specified Bitmap object.
void CChildView::DrawMandelbrot(BitmapPtr pBitmap)
{
   if (pBitmap == NULL)
      return;

   // Get the size of the bitmap.
   const UINT width = pBitmap->GetWidth();
   const UINT height = pBitmap->GetHeight();

   // Return if either width or height is zero.
   if (width == 0 || height == 0)
      return;

   // Lock the bitmap into system memory.
   BitmapData bitmapData;   
   Rect rectBmp(0, 0, width, height);
   pBitmap->LockBits(&rectBmp, ImageLockModeWrite, PixelFormat32bppRGB, 
      &bitmapData);

   // Obtain a pointer to the bitmap bits.
   int* bits = reinterpret_cast<int*>(bitmapData.Scan0);
      
   // Real and imaginary bounds of the complex plane.
   double re_min = -2.1;
   double re_max = 1.0;
   double im_min = -1.3;
   double im_max = 1.3;

   // Factors for mapping from image coordinates to coordinates on the complex plane.
   double re_factor = (re_max - re_min) / (width - 1);
   double im_factor = (im_max - im_min) / (height - 1);

   // The maximum number of iterations to perform on each point.
   const UINT max_iterations = 1000;
   
   // Compute whether each point lies in the Mandelbrot set.
   for (UINT row = 0u; row < height; ++row)
   {
      // Obtain a pointer to the bitmap bits for the current row.
      int *destPixel = bits + (row * width);

      // Convert from image coordinate to coordinate on the complex plane.
      double y0 = im_max - (row * im_factor);

      for (UINT col = 0u; col < width; ++col)
      {
         // Convert from image coordinate to coordinate on the complex plane.
         double x0 = re_min + col * re_factor;

         double x = x0;
         double y = y0;

         UINT iter = 0;
         double x_sq, y_sq;
         while (iter < max_iterations && ((x_sq = x*x) + (y_sq = y*y) < 4))
         {
            double temp = x_sq - y_sq + x0;
            y = 2 * x * y + y0;
            x = temp;
            ++iter;
         }

         // If the point is in the set (or approximately close to it), color
         // the pixel black.
         if(iter == max_iterations) 
         {         
            *destPixel = 0;
         }
         // Otherwise, select a color that is based on the current iteration.
         else
         {
            BYTE red = static_cast<BYTE>((iter % 64) * 4);
            *destPixel = red<<16;
         }

         // Move to the next point.
         ++destPixel;
      }
   }

   // Unlock the bitmap from system memory.
   pBitmap->UnlockBits(&bitmapData);
}

// 7. 实现 CChildView::OnPaint 方法。 此方法将调用 CChildView::DrawMandelbrot,
// 然后将 Bitmap 对象的内容复制到窗口。
void CChildView::OnPaint() 
{
   CPaintDC dc(this); // device context for painting

   // Get the size of the client area of the window.
   RECT rc;
   GetClientRect(&rc);

   // Create a Bitmap object that has the width and height of 
   // the client area.
   BitmapPtr pBitmap(new Bitmap(rc.right, rc.bottom));

   if (pBitmap != NULL)
   {
      // Draw the Mandelbrot fractal to the bitmap.
      DrawMandelbrot(pBitmap);

      // Draw the bitmap to the client area.
      Graphics g(dc);
      g.DrawImage(pBitmap.get(), 0, 0);
   }
}
// 8. 通过生成并运行应用程序来验证其是否已成功更新。

下图显示了 Mandelbrot 应用程序的结果。 

a35a42fc7fc640e89adca095f1b1bd7a.png

由于每个像素的计算成本很高,因此在总体计算完成之前,UI 线程无法处理其他消息。 这可能会降低应用程序的响应能力。 但是,可以通过从 UI 线程中移除工作来缓解此问题。


http://www.kler.cn/news/340902.html

相关文章:

  • AutoKey:开启高效办公与生活的自动化之门
  • 如何评估和选择适合企业的非结构化数据管理工具
  • mybatis-plus转换数据库json类型数据为java对象
  • 力扣题解( 规定时间内到达终点的最小花费)
  • 【LeetCode: 134. 加油站 | 贪心算法】
  • ​el-table去除表格表头多选框或者更换为文字​
  • 【嵌入式软件-STM32】STM32简介
  • 物联网:一种有能力重塑世界的技术
  • 毕业设计选题:基于ssm+vue+uniapp的科创微应用平台小程序
  • Vue集成echarts实现统计图表
  • 【公共祖先】二叉树专题
  • Clickhouse之更新表(ReplacingMergeTree)
  • k8s各类控制器详解
  • RecBole:AttributeError: module ‘ray.tune’ has no attribute ‘report’
  • Ansible 中的 Role
  • PyTorch搭建GNN(GCN、GraphSAGE和GAT)实现多节点、单节点内多变量输入多变量输出时空预测
  • 快速生成单元测试
  • 常用的devops工具集成方法
  • C# 基于winform 使用NI-VISA USB口远程控制电源 万用表
  • vue中的keep-alive用过吗?什么是keep-alive?