采用CreateThread()创建多线程程序
在window环境下,Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作:
1、主要的函数列表:
序号 |
函数名 |
功能 |
1 |
CreateThread() |
创建一个新线程 |
2 |
ExitThread() |
正常结束一个线程的执行 |
3 |
TerminateThead() |
强制终止一个线程的执行 |
4 |
ResumeThread() |
重启一个线程 |
5 |
SuspendThread() |
挂起一个线程 |
6 |
GetExiCodeThread() |
得到一个线程的退出码 |
7 |
GetThreadPriority() |
得到一个线程的优先级 |
8 |
SetThreadPriority() |
设置一个线程的优先级 |
9 |
CloseHandle() |
关闭一个线程的句柄 |
10 |
CreateRemoteThread() |
再另一个进程中创建一个新线程 |
11 |
PostThreadMessage() |
发送一条消息给指定的线程 |
12 |
GetCurrentThread() |
得到当前的线程句柄 |
13 |
GetCurrentThreadId() |
得到当前线程的ID |
14 |
GetThreadId() |
得到指定线程的ID |
15 |
WaitForSingleObject() |
等待单个对象 |
16 |
WaitForMultipleObjects() |
等待多个对象 |
关于多线程的API函数还有很多,以上只是列出了一些比较常用的函数,欲知更多函数和函数的使用方法,请参考MSDN或网络资源,在此就不再介绍了。
2、线程函数的定义:
线程函数的规范格式定义为
DWORD WINAPI ThreadProc (LPVOID lpParam);//格式不正确将无法调用成功。函数名称没有限制,只要符合命名规则就可以。
但我常常看到有下列的线程函数定义:
void ThreadProc ();//该格式也是可以的,但使用的时候要这样通过
LPTHREAD_START_ROUTINE转换,如:
(LPTHREAD_START_ROUTINE)ThreadProc
我建议还是使用规范的格式比较好,不推荐使用void ThreadProc ()格式。不信就请看看MSDN的说明吧:
Do not declare this callback function with a void return typeand cast the function pointer to LPTHREAD_START_ROUTINE when creatingthe thread. Code that does this is common, but it can crash on 64-bit Windows.
而且线程函数必须是全局函数,不能在类中声明和定义。
3、多线程实例1:
我在此将写一个简单的多线程程序,用以展示多线程的功能和使用方法。该程序的主要的思想是画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;
}
运行效果:
单线程测试
多线程测试
工程源码下载地址:
http://download.csdn.net/detail/cbnotes/4857152
欢迎大家修改和指正。
注意事项:
(1)传递给线程执行函数的参数不能是局部变量,而且必须是参数的地址。如:
Int nOffset = 10;
CreateThread(NULL,0,ThreadProc,nOffset,0,&dwThreadID[i]);//错误
CreateThread(NULL,0,ThreadProc,&nOffset,0,&dwThreadID[i]);//错误
Int *pOffset = newint(10);
CreateThread(NULL,0,ThreadProc,pOffset,0,&dwThreadID[i]);//正确
(2)线程执行函数必须是全局函数。
(3)请大家改改下面的程序,且解释下为什么?
这是我开始写程序遇到的一个问题,
改写上面的函数:只是将结构体中一个参数改为CDC指针,以便直接调用。
struct threadInfo
{
CDC * dc; //画布
int nOffset; //偏移量
COLORREF clrRGB; //颜色
};
//多线程测试