windows编程 使用C++实现多线程类
2015-05-07 18:57
513 查看
本文简单介绍如何在windows编程中实现多线程类,供大家学习参考,也希望大家指正。
有时候我们想在一个类中实现多线程,主线程在某些时刻获得数据,可以“通知”子线程去处理,然后把结果返回。下面的实例是主线程每隔2s产生10个随机数,将这10随机数传给多线程类,让它接收到数据后马上打印出来。
首先看类的定义:
类中使用到了ALT类,需要包含atlbase.h和altsync.h头文件。函数TestThread必须是静态函数,因为CreateThread只接受全局或者静态函数。
首先先看Init()和UnInit()函数的实现:
ATL::CEvent的成员函数Create接收4个参数,第四个参数指定Event的名字(它是可以有名字的),以便在其他进程可以找到该事件,这里我们不需要使用,把它设置为NULL,其他参数很容易理解,不赘述。
Init()函数值得注意的是我们创建的线程是以挂起的方式创建,所以必须调用ResumeThread唤醒线程,否则线程一值处于沉睡状态,不执行线程函数。
UnInit()函数比较简单,主要通知线程执行收尾工作,并释放类的资源。
下面我们来看看剩下的函数的实现。
首先我们看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函数的实现:
这段代码就不用解释了,记得包含头文件windows.h、time.h和vector。
总结:
多线程类的使用场景是,当一个线程或得到数据后,希望其他线程能够处理这部分数。多线程类实现还是比较简单的,首先创建线程和线程事件,实现给外部调用的接口,外部通过接口设置事件,通知线程执行。
下一篇文章可能会将更复杂的多线程使用场景,涉及到多线程同步等技术。
有时候我们想在一个类中实现多线程,主线程在某些时刻获得数据,可以“通知”子线程去处理,然后把结果返回。下面的实例是主线程每隔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 c++使用hiredis同步模式实现发布订阅
- Windows编程_Lesson004_项目预备_异步IO操作(使用IOCP实现大文件拷贝的项目)
- vs2013中使用matlab2014b引擎实现c++和matlab混合编程
- C++成员函数实现在类定义中与在类定义外的区别(Windows下直接使用g++)
- windows下,C++实现串口编程,串间口转发数据
- C++使用socket套接字的通信编程实现
- 网络编程(52)—— Windows下使用WSAEventSelect实现异步通知IO
- [置顶] windows环境下用c++实现socket编程
- 【教你抢课】C++网络编程之使用Winsock2实现教务系统自动抢课程序
- 使用C++实现一款Windows平台上的小型FTP服务器
- C/C++ -- Gui编程 -- Qt库的使用 -- 纯代码实现信号槽
- windows下VS2010中使用netcdf的C++接口实现.nc文件的读写
- Windows编程 - 遍历程序使用的动态链接库(dll) 代码(C++)
- 【Socket编程】使用C++实现Server端和Client端
- UDP Socket编程 C/C++实现 (Windows Platform SDK)
- C++学习:使用libssh2实现交互式shell的ssh2,linux和windows通用
- 使用#ifdef _cplusplus 实现c 和 c++的混合编程
- socket编程之UDP(windows环境下C++实现)
- socket编程之组播实现(windows下c++实现)