C++ 之win32多线程应用总结

news2024/11/16 1:37:16

InterlockedIncrement

函数的作用:

在多线程同时对一个变量访问时,保证一个线程访问变量时其他线程不能访问

  • 事件是很常用的多线程同步互斥机制
HANDLE CreateEvent(

 LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL
 BOOL bManualReset,     // 手动/自动
                                     // TRUE:表示手动,在WaitForSingleObject后必须手动调用ResetEvent清除信号
                                    // FALSE:表示自动,在WaitForSingleObject后,系统自动清除事件信号
 BOOL bInitialState,        //初始状态,FALSE为无信号,TRUE为有信号
 LPCTSTR lpName         //事件的名称
    );

下边是使用演示:
在这里插入图片描述

在这里插入图片描述

CreateThread

  • 采用CreateThread()创建多线程程序,参考https://blog.csdn.net/cbnotes/article/details/8277180/在这里插入图片描述
  • 多线程实例

在此将写一个简单的多线程程序,用以展示多线程的功能和使用方法。该程序的主要的思想是画3个进度条,分别以多线程和单线程方式完成,大家可以比较一下。

说明:

(1)该程序还将和单线程做对比。

(2)由于给线程的函数传递了多个参数,所以采用结构体的方式传递参数。

(3)为了演示效果,采用了比较耗时的打点处理。

//线程函数声明
DWORD WINAPI ThreadProc(LPVOIDlpParam);
//为了传递多个参数,我采用结构体
struct threadInfo
{
    HWND hWnd;       //窗口句柄
    int  nOffset;    //偏移量
    COLORREF clrRGB; //颜色
};
 
protected:
HANDLE hThead[3];    //用于存储线程句柄
    DWORD  dwThreadID[3];//用于存储线程的ID
  threadInfo Info[3];   //传递给线程处理函数的参数
//----> 代码实现

//单线程测试
void CMultiThread_1Dlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    //使能按钮
    GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
    GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
    CDC *dc = GetDC();
    CRect rt;
    GetClientRect(rt);
    dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景
    dc->TextOut(97,470,"#1");
    dc->TextOut(297,470,"#2");
    dc->TextOut(497,470,"#3");
    //#1
    for (int i=0;i<460;i++)
    {
       for (int j =10 ;j<200;j++)
       {
           dc->SetPixel(j,460-i,RGB(255,0,0));
       }
    }
    //#2
    for (int i=0;i<460;i++)
    {
       for (int j =210 ;j<400;j++)
        {
           dc->SetPixel(j,460-i,RGB(0,255,0));
       }
    }
    //#3
    for (int i=0;i<460;i++)
    {
       for (int j =410 ;j<600;j++)
       {
           dc->SetPixel(j,460-i,RGB(0,0,255));
       }
    }
    ReleaseDC(dc);
    //使能按钮
    GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
    GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);
}
 
//多线程测试
void CMultiThread_1Dlg::OnBnClickedButton2()
{
    // TODO: 在此添加控件通知处理程序代码
    CDC *dc = GetDC();
    CRect rt;
    GetClientRect(rt);
    dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景
    dc->TextOut(97,470,"#1");
    dc->TextOut(297,470,"#2");
    dc->TextOut(497,470,"#3");
    //初始化线程的参数
    Info[0].hWnd = Info[1].hWnd = Info[2].hWnd = GetSafeHwnd();
    Info[0].nOffset = 10;Info[1].nOffset = 210;Info[2].nOffset = 410;
    Info[0].clrRGB = RGB(255,0,0);Info[1].clrRGB= RGB(0,255,0);Info[2].clrRGB = RGB(0,0,255);
    //创建线程
    for (int i = 0;i<3;i++)
    {
       hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);
    }
    ReleaseDC(dc);
}
 
DWORD WINAPI ThreadProc(LPVOIDlpParam)
{
    threadInfo*Info = (threadInfo*)lpParam;
    CDC *dc = CWnd::FromHandle(Info->hWnd)->GetDC();
    for (int i=0;i<460;i++)
    {
       for (int j=Info->nOffset;j<Info->nOffset+190;j++)
       {
           dc->SetPixel(j,460-i,Info->clrRGB);
       }
    }
    DeleteObject(dc);
    return 0;
}

测试效果如下:
在这里插入图片描述
在这里插入图片描述

GetMessage

  • GetMessage是从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMessage寄送的线程消息。此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。
  • GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax)
参数:
lpMsg:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
hWnd:取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息,
      线程消息通过PostThreadMessage寄送给调用线程。
wMsgFilterMin:指定被检索的最小消息值的整数。
wMsgFilterMax:指定被检索的最大消息值的整数。
返回值:如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。
     如果出现了错误,返回值是-1。例如,当hWnd是无效的窗口句柄或lpMsg是无效的指针时。
     若想获得更多   的错误信息,请调用GetLastError函数。

PeekMessage

  • PeekMessage 调用的一个例子:
PeekMessage(&msg,NULL,0,0,PM_REMOVE);

前面的4个参数(一个指向 MSG 结构的指针、一个窗口的句柄、两个值指示消息范围)与 GetMessage 的参数相同。
将第二、三、四个参数设置为 NULL 或 0时,表明我们想让 PeekMessage 返回程序中所有窗口的所有消息。

如果要将消息从消息队列中删除,则将 PeekMessage 的最后一个参数设置为 PM_REMOVE。
如果不希望删除消息,则将最后一个参数设置为 PM_NOREMOVE,这使得程序可以检查程序的消息队列中的下一个消息,而不实际删除它。

GetMessage 不将控制返回给程序,直到从程序的消息队列中获取消息,但是 PeekMessage 总是立刻返回,而不论一个消息是否出现。
当(应用程序的)消息队列中有一个消息时,PeekMessage 的返回值为 TRUE(非0),并且将按通常方式处理消息。当队列中没有消息时,PeekMessage 返回 FALSE(0)。
考虑如下例子:

// 普通的消息循环 
while( GetMessage(&msg,NULL,0,0) )
{
  TranslateMessage(&msg);
  DispatchMessage (&msg);
}
return msg.wParam;

// 等价于
while( TRUE )
{
  if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
  {
    if(msg.message == WM_QUIT)
    {
      break;
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  else
  {
    // Other program lines to do some work
  }
}
return msg.wParam;

如果 PeekMessage 的返回值为 TRUE,则消息按通常方式进行处理。如果返回值为 FALSE,则在将控制返回给Windows(操作系统) 之前,还可以做一点工作(如显示另一个随机矩形)。

PeekMessage 不能从消息队列中删除 WM_PAINT 消息。
从队列中删除 WM_PAINT 消息的唯一方法是令窗口客户区的失效区域变得有效,这可以用 ValidateRect 和 ValidateRgn 或者 BeginPaint 和 EndPaint 对来完成。

不能使用如下所示的代码来清除消息队列中的所有消息:
while( PeekMessage(&msg,NULL,0,0,PM_REMOVE) );
这条语句从消息队列中删除 WM_PAINT 之外的所有消息。如果队列中有一个 WM_PAINT 消息,程序就会永远地陷在 while 循环中。

WaitForSingleObject

  • 等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);

当线程调用该函数时,第一个参数hObject标识一个能够支持被通知/未通知的内核对象。第二个参数dwMilliseconds.允许该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。

  • 调用下面这个函数将告诉系统,调用函数准备等待到hProcess句柄标识的进程终止运行为止:
WaitForSingleObject(hProcess, INFINITE);

第二个参数告诉系统,调用线程愿意永远等待下去(无限时间量),直到该进程终止运行。
通常情况下, INFINITE是作为第二个参数传递给WaitForSingleObject的,不过也可以传递任何一个值(以毫秒计算)。顺便说一下, INFINITE已经定义为0xFFFFFFFF(或-1)。当然,传递INFINITE有些危险。如果对象永远不变为已通知状态,那么调用线程永远不会被唤醒,它将永远处于死锁状态,
不过,它不会浪费宝贵的CPU时间。

  • 下面是如何用一个超时值而不是INFINITE来调用WaitForSingleObject的例子:
DWORD dw = WaitForSingleObject(hProcess, 5000);
switch(dw)
{
   case WAIT_OBJECT_0:
      // The process terminated.
      break;
   case WAIT_TIMEOUT:
      // The process did not terminate within 5000 milliseconds.
      break;
   case WAIT_FAILED:
      // Bad call to function (invalid handle?)
      break;
}

上面这个代码告诉系统,在特定的进程终止运行之前,或者在5 0 0 0 m s时间结束之前,调用线程不应该变为可调度状态。因此,如果进程终止运行,那么这个
函数调用将在不到5000ms的时间内返回,如果进程尚未终止运行,那么它在大约5000ms时间内返回。注意,不能为dwMilliseconds传递0。如果传递了0,WaitForSingleObject函数将总是立即返回。WaitForSingleObject的返回值能够指明调用线程为什么再次变为可调度状态。如果线程等待的对象变为已通知状态,那么返回值是WAIT_OBJECT_0。如果设置的超时已经到期,则返回值是WAIT_TIMEOUT。如果将一个错误的值(如一个无效句柄)传递给WaitForSingleObject,那么返回值将是WAIT_FAILED(若要了解详细信息,可调用GetLastError)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1247848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

长文讲清荧光定量PCR(最新版)q-pcr rt-pcr

为讲透qPCR&#xff0c;我会持续更新本文&#xff0c;点关注追踪查看。 1.初阶认识 这个阶段&#xff0c;我们要明白一些概念和术语&#xff0c;避免自己在师兄面前错误的瞎哔哔&#xff0c;比如&#xff1a; 问&#xff1a;RT-PCR、qPCR、Real-time PCR、real-time RT-PCR有…

青云科技容器平台与星辰天合存储产品完成兼容性互认证

近日&#xff0c; 北京青云科技股份有限公司&#xff08;以下简称&#xff1a;青云科技&#xff09;的 KubeSphere 企业版容器平台成功完成了与 XSKY星辰天合的企业级分布式统一数据平台 V6&#xff08;简称&#xff1a;XEDP&#xff09;以及天合翔宇分布式存储系统 V6&#xf…

python——第十二天

内置模块或者其他模块学习方式&#xff1a; dir help os模块负责程序与操作系统的交互&#xff0c;提供了访问操作系统底层的接口&#xff1b;即os模块提供了非常丰富的方法用来处理文件和目录。 os&#xff1a; os.path 遍历C盘代码 import os from os import path def …

0003Java程序设计-ssm基于微信小程序的家教信息管理系统

文章目录 摘要目 录系统实现开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 本文讲述了基于微信小程序的家教信息管理系统的设计与实现。结合线上管理的特点&#xff0c;分析了家教信息管理系统的现状&#xff0c;给出…

leetcode:环形链表的入环点

题目描述 题目链接:力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目分析 我们假设起点到环的入口点的距离是L&#xff0c;入口点到相遇点的距离是X&#xff0c;环的长度是C 那么画图我们可以得知&#xff1a; 从开始到相遇时slow走的距离是LX从…

qRT-PCR相对定量计算详解qPCR相对定量计算方式——2^-(∆∆Ct) deta t

做完转录组分析之后&#xff0c;一般都要求做qRT-PCR来验证二代测序得到的转录本表达是否可靠。荧光定量PCR是一种相对表达定量的方法&#xff0c;他的计算方法有很多&#xff0c;常用的相对定量数据分析方法有双标曲线法&#xff0c;ΔCt法&#xff0c;2^-ΔΔCt法(Livak法)&a…

STM32入门笔记15_PWR电源管理模块

PWR和低功耗模式 PWR简介 PWR(Power Control) 电源控制PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压检测器和低功耗模式的功能可编程电压检测器(PVD) 可以监控VDD电源电压&#xff0c;当VDD下降到PVD阈值以下或上升到PVD阈值之上时&#xff0c;PVD会触…

通过线性回归进行房价预测

房价预测一直是房地产行业和投资者关注的重要问题。线性回归是一种常用的回归算法&#xff0c;可以建立输入变量和连续输出变量之间的关系。在本文中&#xff0c;我们将探讨如何使用线性回归算法来进行房价预测&#xff0c;并介绍该方法的步骤和实践技巧。 一、线性回归算法简…

多回路交流三相单相电压电流电量监测开口式互感器适用多种环境用电能耗监控

1 产品概述 多回路交流无线电压电流传感器/电量采集监测仪搭配多路开口式互感器&#xff0c;可以监控采集三相电压、电流、功率和电量等信息&#xff0c;可用于能耗采集监控。支持RS485和4G网络接口&#xff0c;数据可以对接客户指定的第三方云平台。本产品可实现单相/三相用电…

Linux应用开发基础知识——I2C应用编程(十三)

一、无需编写驱动程序即可访问 I2C 设备 APP 访问硬件肯定是需要驱动程序的&#xff0c;对于 I2C 设备&#xff0c;内核提供了驱动程序 drivers/i2c/i2c-dev.c&#xff0c;通过它可以直接使用下面的 I2C 控制器驱动程序来访问 I2C 设备。 i2c-tools 是一套好用的工具&#xff0…

毅速:复杂零件制造首选3D打印

确金属3D打印技术在制造行业的应用日益广泛&#xff0c;为制造业带来了巨大的变革和机遇。这种增材制造技术相较于传统制造工艺具有许多优势&#xff0c;尤其在制造复杂形状零件方面表现出色。 传统制造工艺在制造复杂形状零件时往往面临诸多挑战&#xff0c;如加工难度大、周期…

SuperMap iDesktopX如何获取简单线的起终端点及坐标

作者&#xff1a;超图研究院技术支持中心-于丁 SuperMap iDesktopX如何获取简单线的起终端点及坐标 在GIS行业应用中&#xff0c;线数据的端点坐标有非常多的用处。 定位和可视化&#xff1a;线数据端点坐标可以用于定位和可视化线要素在空间中的位置。这对于地图制作、规划和…

中文地址命名实体识别训练和预测

效果 github项目地址 https://github.com/taishan1994/pytorch_bert_bilstm_crf_ner 下载项目 放在这个位置“F:\Python\github\ultralytics-main\submain\pytorch_bert_bilstm_crf_ner-main” 训练和预测步骤 1、下载数据集 从github项目可以找到数据集下载地址 https:…

Youtube0播放?运营教你需要的技巧、策略与工具!

对于有跨境意向的内容创作者或者品牌企业来说&#xff0c;YouTube是因其巨大的潜在受众群和商业价值成为最值得投入变现与营销计划的平台。 据统计&#xff0c;98% 的美国人每月访问 YouTube&#xff0c;近三分之二的人每天访问。但是&#xff0c;YouTube还远未达到过度饱和的…

Python 哈希表的实现——字典

哈喽大家好&#xff0c;我是咸鱼 接触过 Python 的小伙伴应该对【字典】这一数据类型都了解吧 虽然 Python 没有显式名称为“哈希表”的内置数据结构&#xff0c;但是字典是哈希表实现的数据结构 在 Python 中&#xff0c;字典的键&#xff08;key&#xff09;被哈希&#x…

处理视频的新工具:UniFab 2.0.0.4 Crack

UniFab这是一个用于处理视频的新工具&#xff0c;可以帮助您像专业人士一样获得结果&#xff0c;事实上&#xff0c;它可以确保在项目的任何设备上完美播放&#xff0c;所以&#xff0c;来认识一下 UniFab - 一款功能强大且方便的视频编辑器和转换器&#xff0c;但另一方面&…

【Spring日志】

一.日志作用 1.定位和发现问题 这是日志的主要用途,通过查看日志,我们可以定位问题发生的位置,从而快速的发现问题,分析问题. 2.系统监控 监控几乎是一个成熟系统的标配,我们可以通过日志记录这个系统的运行状态,比如记录方法的响应时间,响应状态,通过设置不同的规则,超过阈值就…

硅光子,缘何打造量子科技的下一个十年?

/目录/ 一、硅光子技术将率先实现室温、容错量子计算机 二、用于量子科技的硅光子器件 2.1. 单光子源 2.2. 光子探测器 2.3. 波分复用技术 2.4. 低温技术 2.5. 芯片互连 三、可拓展的量子信息应用 3.1. 多光子和高维应用 3.2. 量子纠错 3.3. 量子密钥分发 3.4. 量子…

Android runtime层是如何通过缩减代码来缩减内存的

文章目录 前言&#xff1a;Android 在设备上改进内存的秘密优化编译器101代码大小改进消除写入障碍隐式暂停检查合并回调其他优化改进代码下沉循环优化消除死代码 – SimplifyAlwaysThrows加载存储消除 – 使用 try catch 块加载存储消除 – 使用释放/获取操作新的内联启发式不…

LiveVIS视图库1400-如何切换数据库?默认使用的数据库是什么?如何切换到Mysql/MariaDB?

LiveVIS视图库1400-如何切换数据库&#xff1f;默认使用的数据库是什么&#xff1f;如何切换到Mysql/MariaDB? 1、切换成Mysql/Mariadb数据库1.1 连接数据库1.2 创建数据库实例1.3 配置.ini文件1.4 重启完成切换 1、切换成Mysql/Mariadb数据库 LiveVIS 默认使用 sqlite3 文件…