有时候我们想在一个类中实现多线程,主线程在某些时刻获得数据,可以“通知”子线程去处理,然后把结果返回。下面的实例是主线程每隔2s产生10个随机数,将这10随机数传给多线程类,让它接收到数据后马上打印出来。

首先看类的定义:

  1. #pragma once
  2. #include <iostream>
  3. #include <atlbase.h>    // 使用到了atl类
  4. #include <atlsync.h>
  5. #include <vector>
  6. using namespace std;
  7. class CMultiThreadTest
  8. {
  9. public:
  10. bool Init();    // 初始化类成员
  11. bool UnInit();  // 释放资源
  12. void NotifyDowork(const std::vector<int> &data);
  13. static DWORD CALLBACK TestThread(LPVOID);   // 线程函数,必须是静态函数
  14. DWORD TestProc();                           // 线程工作实现
  15. private:
  16. std::vector<int> m_data;    // 同步数据
  17. ATL::CEvent m_NotifyEvent;  // 通知事件
  18. HANDLE m_hThread;           // 线程句柄
  19. };

类中使用到了ALT类,需要包含atlbase.h和altsync.h头文件。函数TestThread必须是静态函数,因为CreateThread只接受全局或者静态函数。
首先先看Init()和UnInit()函数的实现:

  1. bool CMultiThreadTest::Init()
  2. {
  3. // 创建事件
  4. BOOL bRet = m_NotifyEvent.Create(NULL, TRUE, FALSE, NULL);
  5. if (!bRet) {
  6. return false;
  7. }
  8. // 挂起的方式创建线程
  9. m_hThread = CreateThread(NULL, 0, &CMultiThreadTest::TestThread, this, CREATE_SUSPENDED, NULL);
  10. if (NULL == m_hThread) {
  11. return false;
  12. }
  13. // 唤醒线程
  14. ResumeThread(m_hThread);
  15. return true;
  16. }
  17. bool CMultiThreadTest::UnInit()
  18. {
  19. // 通知线程处理data的数据
  20. if (m_NotifyEvent != NULL) {
  21. m_NotifyEvent.Set();
  22. }
  23. if (m_hThread != NULL)
  24. {
  25. // 预留100ms让线程处理完数据,100ms是个估值
  26. WaitForSingleObject(m_hThread, 100);
  27. CloseHandle(m_hThread);
  28. m_hThread = NULL;
  29. }
  30. return true;
  31. }

ATL::CEvent的成员函数Create接收4个参数,第四个参数指定Event的名字(它是可以有名字的),以便在其他进程可以找到该事件,这里我们不需要使用,把它设置为NULL,其他参数很容易理解,不赘述。
Init()函数值得注意的是我们创建的线程是以挂起的方式创建,所以必须调用ResumeThread唤醒线程,否则线程一值处于沉睡状态,不执行线程函数。
UnInit()函数比较简单,主要通知线程执行收尾工作,并释放类的资源。

下面我们来看看剩下的函数的实现。

  1. DWORD CALLBACK CMultiThreadTest::TestThread(LPVOID lpParam)
  2. {
  3. if (lpParam == NULL) {
  4. return 0;
  5. }
  6. CMultiThreadTest *lpThis = reinterpret_cast<CMultiThreadTest *>(lpParam);
  7. return lpThis->TestProc();
  8. }
  9. DWORD CMultiThreadTest::TestProc()
  10. {
  11. while (true)
  12. {
  13. // 每5s监听一次,秒数直接影响程序的性能
  14. DWORD dwRet = WaitForSingleObject(m_NotifyEvent, 5000);
  15. // 进入循环5s没有事件发生,不做任何处理
  16. if (dwRet == WAIT_TIMEOUT) {
  17. continue;
  18. }
  19. // 打印数组
  20. for (unsigned int i = 0; i < m_data.size(); i++)
  21. {
  22. cout <<m_data[i] <<" ";
  23. }
  24. cout <<endl;
  25. // 重置事件
  26. m_NotifyEvent.Reset();
  27. }
  28. return 0;
  29. }
  30. void CMultiThreadTest::NotifyDowork(const std::vector<int> &data)
  31. {
  32. m_data = data;
  33. m_NotifyEvent.Set();    // 通知线程该做事情了!
  34. }

首先我们看TestThread函数,它是线程的“入口“,线程被唤醒后执行该函数。值得注意的是,我们在创建线程的时候把对象指针this作为参数传递给创建线程函数,系统在调用TestThread的时候会把this传递回来,这里使用弱类型转换reinterpret_cast将LPVOID转化为CMultiThreadTest类的指针,reinterpret_cast是一个危险的类型转换,一般只适用于指针和整数之间的转换。有兴趣的同学可以参考C++ Primer第4版18.2.1章节。

线程函数将参数lpParam转化为对象指针后,执行对象的成员函数TestProc(),TestProc()实现主要的逻辑。这里可能会有人疑问,为什么不直接在TestThread()函数实现主要逻辑呢?这样做有两个好处,一是能够将线程函数逻辑和业务逻辑分离,其二就是TestThread是个静态函数,类静态函数只能处理类的静态成员变量,而很多时候我们希望线程处理类的非静态成员变量。
最后NotifyDowork函数很简单,该函数给外部调用,它把外部传进来的data赋值给类的非静态成员变量m_data,并通知线程处理m_data数据,TestProc中WaitForSingleObject函数接收到事件后往下执行,把m_data打印出来。

下面我们看看main函数的实现:

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. CMultiThreadTest multiThreadTest;
  4. // 初始化失败
  5. if (!multiThreadTest.Init()) {
  6. return 0;
  7. }
  8. srand(unsigned int(time(NULL)));
  9. std::vector<int> data;
  10. while (true)
  11. {
  12. data.clear();
  13. // 产生10个随机数
  14. for (int i = 0; i < 10; i++)
  15. data.push_back(rand() % 1000);
  16. // 通知多线程类执行工作
  17. multiThreadTest.NotifyDowork(data);
  18. Sleep(2000);
  19. }
  20. multiThreadTest.UnInit();
  21. return 0;
  22. }

这段代码就不用解释了,记得包含头文件windows.h、time.h和vector。

总结:
多线程类的使用场景是,当一个线程或得到数据后,希望其他线程能够处理这部分数。多线程类实现还是比较简单的,首先创建线程和线程事件,实现给外部调用的接口,外部通过接口设置事件,通知线程执行。

windows编程 使用C++实现多线程类的更多相关文章

  1. 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

    [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...

  2. 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress

    [源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...

  3. C++实现多线程类Thread

    Windows编程中创建线程的常见函数有:CreateThread._beginthread._beginthreadex.据说在任何情况下_beginthreadex都是较好的选择. _begint ...

  4. delphi 线程教学第四节:多线程类的改进

    第四节:多线程类的改进   1.需要改进的地方   a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...

  5. [转帖]Windows和Linux对决(多进程多线程)

    Windows和Linux对决(多进程多线程) https://blog.csdn.net/world_2015/article/details/44920467 太长了 还没看完.. 还是没太理解好 ...

  6. MoreWindows 微软认证专家博客目录(白话算法,C++ STL,windows编程)

    为了方便大家查找和学习,现将本人博客中所有博客文章列出目录. (http://blog.csdn.net/morewindows) 一.      白话经典算法 目前有17篇,分为七大排序和经典面试题 ...

  7. windows编程经典书籍

    本人是刚刚开始学习windows编程的,感觉看雪学院的大牛很NB.想找一些书籍来看学习学习,可是不知道看哪些书好.驱动,对菜鸟们来说真是一个很深奥的话题,所以 ,我找来了这篇文章供大家分享,以后大家发 ...

  8. 【Windows编程】系列第十一篇:多文档界面框架

    前面我们所举的例子中都是单文档界面框架,也就是说这个窗口里面的客户区就是一个文档界面,可以编写程序在里面输入或者绘制文本和图形输出,但是不能有出现多个文档的情况.比如下面的UltraEdit就是一个典 ...

  9. Windows编程入门程序详解

    引用:http://blog.csdn.net/jarvischu/article/details/8115390 1.     程序 /******************************* ...

随机推荐

  1. [Go] 使用读写锁对map资源进行安全处理

    当需要有一个全局性的map集合资源进行增删改数据时,需要对该map资源增加读写锁,防止并发时出现安全问题 下面的类就是举例 , 属性中的Conns模拟存储一些资源,对这些资源进行并发的增加数据,使用写 ...

  2. MaxCompute - ODPS重装上阵 第六弹 - User Defined Type

    MaxCompute(原ODPS)是阿里云自主研发的具有业界领先水平的分布式大数据处理平台, 尤其在集团内部得到广泛应用,支撑了多个BU的核心业务. MaxCompute除了持续优化性能外,也致力于提 ...

  3. wx小程序知识点(一)

    一.微信小程序中的目录及文件 (1)project.config.json 用于开发者工具配置 主要用于设置项目是否开启https校验(setting.urlCheck) (2) App.js 设置全 ...

  4. 计蒜客 window画图

    在 Windows 的"画图"工具里,可以绘制各种各样的图案.可以把画图当做一个标准的二维平面,在其上先后绘制了 nn 条颜色互不相同的线段. 输出格式 输出 qq 行,每行一个整 ...

  5. ID生成 雪花算法

    /** * ID生成 雪花算法 */ public class SnowFlake { public static SnowFlake getInstance() { return Singleton ...

  6. python3 使用装饰器,及函数作为参数

    #装饰import typesdef shucai(n): print('蔬菜价格7') if type(n)==types.FunctionType: return n()+7 return n+7 ...

  7. Excel导入导出工具(简单、好用且轻量级的海量Excel文件导入导出解决方案.)

    Excel导入导出工具(简单.好用且轻量级的海量Excel文件导入导出解决方案.) 置顶 2019-09-07 16:47:10 $9420 阅读数 261更多 分类专栏: java   版权声明:本 ...

  8. java @Value注解 和 @Data注解

    @Value注解 service层代码 @Service public class HelloServiceImpl implements HelloService { @Autowired priv ...

  9. 从零开始学习vue(2)

    一.vue实例 每个vue应用都是通过Vue构造函数创建的一个新的实例开始的: var vm = new Vue({ //选项对象 }) 在这其中vm(viewModel的简称)通常都表示vue实例的 ...

  10. 并发量,tps,qps

    QPS/TPS/并发量/系统吞吐量的概念 2017年08月13日 17:24:47 阅读数:10682 我们在日常工作中经常会听到QPS/TPS这些名词,也会经常被别人问起说你的系统吞吐量有多大.这个 ...