Win32多线程类
来源:互联网 发布:淘宝网人工客服电话 编辑:程序博客网 时间:2024/05/16 11:50
Win32多线程类
前些时候用CUDA做了个加速三维配准的程序,做的结果很是让人郁闷,在一个四核CPU和9600GT显卡上运行的速度差不多,偏偏对方又规定了不能换更高档的显卡,于是决定改用CPU多线程来做并行计算,结果还不错,于是把程序写成了win32多线程的类,封装在DLL中。下面介绍一下怎么写多线程的类,如果有错误的话希望大家指正。
首先是关于Win32多线程的一些基本知识,包括线程创建和同步等,更详细的内容大家可以在清华大学出版社的《多核程序设计》中找到。对多线程编程有过初步了解的可以直接跳过这一部分。
Win32API中用于创建线程的主要有两个函数,一个是定义在Windows.h中的CreateThread,另外一个是定义在process.h中的_beginthread函数。这里我用的是形式比较简单的_beginthread函数。
线程同步主要以下面几种方式实现:全局变量,事件,临界区,互斥量和信号量,采用哪种方式取决于要用多线程做什么。例如用事件做线程同步的话,需要调用CreateEvent和WaitForSingleObject两个函数。
另外,还可以用SetThreadPriority设置线程的优先级,用SuspendThread和ResumeThread挂起和恢复线程,用WaitForSingleObject和WaitForMultipleObject实现线程等待,用ExitThread和TerminateThread强制终止线程。
在了解了多线程编程以后,就可以继续讲封装了多线程的类的编写了。
首先新建一个空的Win32控制台应用程序,用类向导在其中添加一个名为CMThread的类,类的代码如下:
//MThread.h
#pragma once
class CMThread
{
public:
CMThread(void);
public:
~CMThread(void);
public:
voidRun(); //创建线程
private:
inta;
intb;
private:
voidThreadA(LPVOIDpParam); //线程A的线程函数
voidThreadB(LPVOIDpParam); //线程B的线程函数
};
//MThread.cpp
#include "MThread.h"
#include <iostream>
#include <process.h>
using namespace std;
CMThread::CMThread(void)
{
a= 0;
b= 1;
}
CMThread::~CMThread(void)
{
}
void CMThread::ThreadA(LPVOID pParam)
{
cout<<"线程"<<a<<"调用成功"<<endl;
}
void CMThread::ThreadB(LPVOID pParam)
{
cout<<"线程"<<b<<"调用成功"<<endl;
}
//创建线程
void CMThread::Run()
{
_beginthread(ThreadA, 0, NULL);
_beginthread(ThreadB, 0, NULL);
}
为了测试多线程类,还需要添加一个main.cpp文件:
//main.cpp
#include "MThread.h"
#include <iostream>
void main()
{
CMThreadmtThread;
mtThread.Run();
}
编译程序,会出现如下错误:
error C3867: 'CMThread::ThreadA':function call missing argument list; use '&CMThread::ThreadA' to create apointer to member
error C3867: 'CMThread::ThreadB':function call missing argument list; use '&CMThread::ThreadB' to create apointer to member
双击错误,会发现是_beginthread(ThreadA, 0, NULL)出错,如果只是从字面上理解,似乎是因为函数指针调用方式错误引起的,但是将ThreadA换成&CMThread::ThreadA时仍然不能运行成功。其实这是因为线程函数必须是全局函数。为此需要将线程声明为static函数。这时候又会出现一个新的问题:static类型的函数中不能访问类中其它的非静态成员!解决这个问题的一种方法是将线程函数中用到的类成员函数和变量都声明为static型,但是这种方法显然不实用。另外一种方法是将类本身作为参数传递到线程函数中,为此,需要对线程函数和Run函数作如下修改:
void CMThread::ThreadA(LPVOID pParam)
{
CMThread*mt = (CMThread*)pParam;
cout<<"线程"<<mt->a<<"调用成功"<<endl;
}
void CMThread::ThreadB(LPVOID pParam)
{
CMThread*mt = (CMThread*)pParam;
cout<<"线程"<<mt->b<<"调用成功"<<endl;
}
//创建线程
void CMThread::Run()
{
_beginthread(ThreadA, 0, this);
_beginthread(ThreadB, 0, this);
}
这个时候再运行程序就不会报错了,但是多运行几次就会发现,每次运行输出的结果只有一半或是完全没有输出(如下图所示)。原来是线程没有同步。
加上线程同步后的代码如下:
//MThread.h
#pragma once
#include <Windows.h>
#include <process.h>
class CMThread
{
public:
CMThread(void);
public:
~CMThread(void);
public:
voidRun(); //创建线程
private:
inta;
intb;
HANDLEevThreadAOver; //用于标识线程A结束的事件
HANDLEevThreadBOver; //用于标识线程B结束的事件
private:
staticvoid ThreadA(LPVOID pParam); //线程A的线程函数
staticvoid ThreadB(LPVOID pParam); //线程B的线程函数
};
//MThread.cpp
#include "MThread.h"
#include <iostream>
using namespace std;
CMThread::CMThread(void)
{
a= 0;
b= 1;
}
CMThread::~CMThread(void)
{
}
void CMThread::ThreadA(LPVOID pParam)
{
CMThread*mt = (CMThread*)pParam;
cout<<"线程"<<mt->a<<"调用成功"<<endl;
SetEvent(mt->evThreadAOver);
}
void CMThread::ThreadB(LPVOID pParam)
{
CMThread*mt = (CMThread*)pParam;
cout<<"线程"<<mt->b<<"调用成功"<<endl;
SetEvent(mt->evThreadBOver);
}
//创建线程
void CMThread::Run()
{
//产生事件
evThreadAOver= CreateEvent(NULL,FALSE, FALSE,NULL);
evThreadBOver= CreateEvent(NULL,FALSE, FALSE,NULL);
//创建线程A和B
_beginthread(ThreadA, 0, this);
_beginthread(ThreadB, 0, this);
//等待线程A和B结束
WaitForSingleObject(evThreadAOver, INFINITE);
WaitForSingleObject(evThreadBOver, INFINITE);
}
//main.cpp
#include "MThread.h"
#include <iostream>
void main()
{
CMThreadmtThread;
mtThread.Run();
}
运行结果如图所示
- Win32多线程类
- Win32多线程
- Win32 多线程
- win32 多线程
- WIN32多线程
- win32 多线程
- Win32 多线程的性能
- Win32 多线程的性能
- Win32多线程程序设计读书笔记
- Win32 多线程的性能
- win32多线程 - 汉诺塔动画
- 《Win32多线程程序设计》
- 《Win32 多线程程序设计》读书笔记
- WIN32上的多线程
- win32多线程编程
- Win32多线程程序设计基本概念
- 深入浅出Win32多线程程序设计
- win32 多线程 1
- 开始
- Linux 学习
- 90-10年计划
- jquery按需加载js和css插件使用说明
- 网页背景颜色
- Win32多线程类
- 生存以上 生活以下
- 小组早晨例会
- reactos操作系统实现(138)
- 绝望之爱——宇智波 鼬
- MFC中如何安全的创建和关闭线程
- VC判断目录是否存在
- 手机游戏介绍
- DLL动态链接库