windows编程 使用C++实现多线程类
有时候我们想在一个类中实现多线程,主线程在某些时刻获得数据,可以“通知”子线程去处理,然后把结果返回。下面的实例是主线程每隔2s产生10个随机数,将这10随机数传给多线程类,让它接收到数据后马上打印出来。
首先看类的定义:
- #pragma once
- #include <iostream>
- #include <atlbase.h> // 使用到了atl类
- #include <atlsync.h>
- #include <vector>
- using namespace std;
- class CMultiThreadTest
- {
- public:
- bool Init(); // 初始化类成员
- bool UnInit(); // 释放资源
- void NotifyDowork(const std::vector<int> &data);
- static DWORD CALLBACK TestThread(LPVOID); // 线程函数,必须是静态函数
- DWORD TestProc(); // 线程工作实现
- private:
- std::vector<int> m_data; // 同步数据
- ATL::CEvent m_NotifyEvent; // 通知事件
- HANDLE m_hThread; // 线程句柄
- };
类中使用到了ALT类,需要包含atlbase.h和altsync.h头文件。函数TestThread必须是静态函数,因为CreateThread只接受全局或者静态函数。
首先先看Init()和UnInit()函数的实现:
- bool CMultiThreadTest::Init()
- {
- // 创建事件
- BOOL bRet = m_NotifyEvent.Create(NULL, TRUE, FALSE, NULL);
- if (!bRet) {
- return false;
- }
- // 挂起的方式创建线程
- m_hThread = CreateThread(NULL, 0, &CMultiThreadTest::TestThread, this, CREATE_SUSPENDED, NULL);
- if (NULL == m_hThread) {
- return false;
- }
- // 唤醒线程
- ResumeThread(m_hThread);
- return true;
- }
- bool CMultiThreadTest::UnInit()
- {
- // 通知线程处理data的数据
- if (m_NotifyEvent != NULL) {
- m_NotifyEvent.Set();
- }
- if (m_hThread != NULL)
- {
- // 预留100ms让线程处理完数据,100ms是个估值
- WaitForSingleObject(m_hThread, 100);
- CloseHandle(m_hThread);
- m_hThread = NULL;
- }
- return true;
- }
ATL::CEvent的成员函数Create接收4个参数,第四个参数指定Event的名字(它是可以有名字的),以便在其他进程可以找到该事件,这里我们不需要使用,把它设置为NULL,其他参数很容易理解,不赘述。
Init()函数值得注意的是我们创建的线程是以挂起的方式创建,所以必须调用ResumeThread唤醒线程,否则线程一值处于沉睡状态,不执行线程函数。
UnInit()函数比较简单,主要通知线程执行收尾工作,并释放类的资源。
下面我们来看看剩下的函数的实现。
- DWORD CALLBACK CMultiThreadTest::TestThread(LPVOID lpParam)
- {
- if (lpParam == NULL) {
- return 0;
- }
- CMultiThreadTest *lpThis = reinterpret_cast<CMultiThreadTest *>(lpParam);
- return lpThis->TestProc();
- }
- DWORD CMultiThreadTest::TestProc()
- {
- while (true)
- {
- // 每5s监听一次,秒数直接影响程序的性能
- DWORD dwRet = WaitForSingleObject(m_NotifyEvent, 5000);
- // 进入循环5s没有事件发生,不做任何处理
- if (dwRet == WAIT_TIMEOUT) {
- continue;
- }
- // 打印数组
- for (unsigned int i = 0; i < m_data.size(); i++)
- {
- cout <<m_data[i] <<" ";
- }
- cout <<endl;
- // 重置事件
- m_NotifyEvent.Reset();
- }
- return 0;
- }
- void CMultiThreadTest::NotifyDowork(const std::vector<int> &data)
- {
- m_data = data;
- m_NotifyEvent.Set(); // 通知线程该做事情了!
- }
首先我们看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函数的实现:
- int _tmain(int argc, _TCHAR* argv[])
- {
- CMultiThreadTest multiThreadTest;
- // 初始化失败
- if (!multiThreadTest.Init()) {
- return 0;
- }
- srand(unsigned int(time(NULL)));
- std::vector<int> data;
- while (true)
- {
- data.clear();
- // 产生10个随机数
- for (int i = 0; i < 10; i++)
- data.push_back(rand() % 1000);
- // 通知多线程类执行工作
- multiThreadTest.NotifyDowork(data);
- Sleep(2000);
- }
- multiThreadTest.UnInit();
- return 0;
- }
这段代码就不用解释了,记得包含头文件windows.h、time.h和vector。
总结:
多线程类的使用场景是,当一个线程或得到数据后,希望其他线程能够处理这部分数。多线程类实现还是比较简单的,首先创建线程和线程事件,实现给外部调用的接口,外部通过接口设置事件,通知线程执行。
windows编程 使用C++实现多线程类的更多相关文章
- 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...
- 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress
[源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...
- C++实现多线程类Thread
Windows编程中创建线程的常见函数有:CreateThread._beginthread._beginthreadex.据说在任何情况下_beginthreadex都是较好的选择. _begint ...
- delphi 线程教学第四节:多线程类的改进
第四节:多线程类的改进 1.需要改进的地方 a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...
- [转帖]Windows和Linux对决(多进程多线程)
Windows和Linux对决(多进程多线程) https://blog.csdn.net/world_2015/article/details/44920467 太长了 还没看完.. 还是没太理解好 ...
- MoreWindows 微软认证专家博客目录(白话算法,C++ STL,windows编程)
为了方便大家查找和学习,现将本人博客中所有博客文章列出目录. (http://blog.csdn.net/morewindows) 一. 白话经典算法 目前有17篇,分为七大排序和经典面试题 ...
- windows编程经典书籍
本人是刚刚开始学习windows编程的,感觉看雪学院的大牛很NB.想找一些书籍来看学习学习,可是不知道看哪些书好.驱动,对菜鸟们来说真是一个很深奥的话题,所以 ,我找来了这篇文章供大家分享,以后大家发 ...
- 【Windows编程】系列第十一篇:多文档界面框架
前面我们所举的例子中都是单文档界面框架,也就是说这个窗口里面的客户区就是一个文档界面,可以编写程序在里面输入或者绘制文本和图形输出,但是不能有出现多个文档的情况.比如下面的UltraEdit就是一个典 ...
- Windows编程入门程序详解
引用:http://blog.csdn.net/jarvischu/article/details/8115390 1. 程序 /******************************* ...
随机推荐
- Tomcat非root身份运行制作Linux系统服务管理
理论知识怱略,马上开始实战 一.首先准备好tomcat 启动.关闭.重启Shell脚本: 以下Shell脚本主要修改值 tomcatPath:tomcat目录 runUser:以哪个身份运行 此处测试 ...
- Linux 打印简单日志(一)
简单日志输出: #include<stdio.h> #include<string.h> #include<stdlib.h> void write(char* f ...
- POJ1703--Find them, Catch them(种类并查集)
Time Limit: 1000MSMemory Limit: 10000K Total Submissions: 32909Accepted: 10158 Description The polic ...
- php mysql替换数据库中出现过的所有域名实现办法 (原)
2019-10-12备注: 数据量稍微有些大且前期数据库建设相当完善的可以看一下这边的方法,数据量小或者数据库建设不完善的可以参考这篇文章,前两天看的,没自己试,有需要可以试试 https://ww ...
- oracle条件参数中 IN函数中的值最大只能为1000个
delete from dep where id in(1,2,3.....) 括号里面字段个数最大只能为1000个
- LeetCode 第 3 题:无重复字符的最长子串(滑动窗口)
LeetCode 第 3 题:无重复字符的最长子串 (滑动窗口) 方法:滑动窗口 滑动窗口模板问题:右指针先走,满足了一定条件以后,左指针向前走,直到不满足条件. 特点:左右指针的方向是一致的,并且是 ...
- Unknown tag (s:property)的原因
今天在做struts2的练习,然后在jsp页面我使用<s:property value="name"/>竟然报错, 然后网上走了下,恍然大悟,我原来没有在jsp页面里面 ...
- mysql 判断时间 语法
今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW ...
- vue中bus.$on事件被多次绑定
问题描述:只要页面没有强制刷新,存在组件切换,bus.$on方法会被多次绑定,造成事件多次触发 解决办法一:在每次调用方法前先解绑事件( bus.$off ),然后在重新绑定( bus.$on ) b ...
- 【转】diamond专题(一)– 简介和快速使用
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...