2024年3月20日发(作者:)
Win32 多线程的创建方法和基本使用
作者: gengshenghong (2 篇文章) 日期: 十二月 2, 2011 在 5:17 下
午
Summary:
总结Win32提供的创建多线程相关的API接口和基本的使用框架。
Ref:
MSDN: /zh-cn/library/y6h8hye8(v=VS.100)
Win32多线程的创建方法主要有:
(1)CreateThread()
(2)_beginthread()&&_beginthreadex()
(3)AfxBeginThread()
(4)CWinThread类
(1)CreateThread()
百度百科:/view/
函数原型:
view plaincopy to clipboardprint?
CreateThread(
02. LPSECURITY_ATTRIBUTES lpThreadAttributes,
03. DWORD dwStackSize,
04. LPTHREAD_START_ROUTINE lpStartAddress,
05. LPVOID lpParameter,
06. DWORD dwCreationFlags,
07. LPDWORD lpThreadId);
08.}
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
}
头文件:Windows.h
CreateThread是Win32提供的创建线程的最基础的API,用于在主线程上创建一
个线程。返回一个HANDLE句柄(内核对象)。
参数简要说明:
lpThreadAttributes:线程属性,用于设置线程的属性,NULL表示使用默认的
设置。dwStackSize:线程堆栈大小,使用0采用默认设置,windows会根据需
要动态增加堆栈大小。lpStartAddress:指向线程函数的指针。lpParameter:
向线程函数传递的参数。dwCreationFlags:线程标志,CREATE_SUSPENDED表示
创建一个挂起的线程,0表示创建后立即激活线程。lpThreadId,先线程的ID
(输出参数)。
创建线程的代码:
view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.
WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread startedn");
07. printf("sub thread finishedn");
08. return 0;
09.}
10.
main(int argc, char* argv[])
12.{
13. DWORD threadID;
14. HANDLE hThread;
15. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创
建线程
16.
17. return 0;
18.}
#include "stdafx.h"
#include
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread startedn");
printf("sub thread finishedn");
return 0;
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线
程
return 0;
}
如果直接使用上面的代码,那么很可能没有任何输出,这是由于主线程创建了子
线程后主线程继续向下运行,子线程还没来得及执行里面的代码主线程可能就结
束了。这就需要另一个API来进行同步:WaitForSingleObject()。
与之对应的还有WaitForMultipleObjects,用于同步一组内核对象。(参考
/zh-cn/site/ms686360获取所有的同步函数
(Synchronization Functions)的使用。
WaitForSingleObject原型:DWORD WINAPI WaitForSingleObject(__in HANDLE
hHandle, __in DWORD dwMilliseconds);其中,第一个参数是要等待的内核对象
的句柄,第二个参数是设置等待超时时间,可以设置为INFINITE,表示一直等
待直到有信号触发。
在内核对象使用完毕后,一般需要关闭,使用CloseHandle()函数,参数为内核
对象句柄。
所以,以下是一个最基本的使用CreateThread的例子:
view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.
WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread startedn");
07. // TODO: Add your thread code here.
08. printf("sub thread finishedn");
09. return 0;
10.}
11.
main(int argc, char* argv[])
13.{
14. DWORD threadID;
15. HANDLE hThread;
16. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创
建线程
17.
18. WaitForSingleObject(hThread,INFINITE);
19. CloseHandle(hThread); // 关闭内核对象
20.
21. return 0;
22.}
#include "stdafx.h"
#include
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread startedn");
// TODO: Add your thread code here.
printf("sub thread finishedn");
return 0;
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线
程
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread); // 关闭内核对象
return 0;
}
(2)_beginthread()&&_beginthreadex()
百度百科:/view/
MSDN:/zh-cn/library/
函数原型:
view plaincopy to clipboardprint?
r_t _beginthread( // NATIVE CODE
02. void( __cdecl *start_address )( void * ),
03. unsigned stack_size,
04. void *arglist
05.);
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);
头文件:process.h
参数说明:第一个参数是线程函数的指针,第二个参数是堆栈大小,第三个参数
是要传递给线程函数的参数列表。返回值也是线程句柄(关于更多说明,参考
MSDN)。
同样,对于_beginthread()的同步,和CreateThread一样可以使用
WaitForSingleObject函数,CloseHandle()关闭内核对象。另外,_beginthread()
的线程函数是无返回值类型的,可以使用_endthread()在线程函数中结束线程。
下面是一个使用_beginthread()的基本的例子:
view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.#include
04.
__cdecl ThreadProc(void *para)
06.{
07. printf("sub thread startedn");
08. // TODO: Add your thread code here.
09. printf("sub thread finishedn");
10. _endthread(); // 可以省略,隐含会调用。
11.}
12.
main(int argc, char* argv[])
14.{
15. HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
16.
17. WaitForSingleObject(hThread,INFINITE);
18. CloseHandle(hThread);
19.}
#include "stdafx.h"
#include
#include
void __cdecl ThreadProc(void *para)
{
printf("sub thread startedn");
// TODO: Add your thread code here.
printf("sub thread finishedn");
_endthread(); // 可以省略,隐含会调用。
}
int main(int argc, char* argv[])
{
HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
}另外,还有一个函数_beginthreadex(),可以简单的认为_beginthread()为其
简化版,所以更多的时候是使用更简单的_beginthread()了。
说明:在MSDN中可以看到一句很重要的提示,内容为“For an executable file
linked with , do not call the Win32 ExitThread API; this
prevents the run-time system from reclaiming allocated resources.
_endthread and _endthreadex reclaim allocated thread resources and then
call ExitThread.”,简单翻译就是说,对于链接的可执行程序,
不要使用Win32的线程退出函数(ExitThread),这会阻止运行时系统回收分配的
资源,应该使用_endthread,它能回收分配的线程资源然后调用ExitThread。
这个问题看似没有提到CreateThread(),但是其实有关,这就是经常看到有些
资料上坚决的说到”不要使用CreateThread创建线程,否则会内存泄漏“的来
源了。
问题引出:CreateThread的内存泄漏问题(CreateThread和_beginthread的区
别)
Related Topics:
/view/
/whiteyun/archive/2011/06/02/ ....
1. _beginthread也是通过CreateThread来创建线程的,只是_beginthread对
其进行了一些封装,将相关”资源“通过线程的本地存储(TLS)传递给了线程
函数的参数,然后在调用_endthread的时候,会将这些保存的资源进行释放。
2. 并不是所有的使用CreateThread的情况都会有内存泄漏。看了很多人的文
章,只有/view/的分
析是最清晰的,我已经转到/c03ljl2iud了,可下载查看
(版权归原作者所有)。
总之,建议是使用_beginthread取代CreateThread来创建线程。
(3)AfxBeginThread():
很显然,这是MFC中的Afx系列函数,一个在MFC中创建线程的全局函数。由于
现在也不怎么用MFC了,这里就不多说了。
(4)CWinThread类:
很显然,是MFC中创建线程的类,同上,不多说了。
欢迎补充!
(1)补充内容:
关于WaitForMultipleObjects在_beginthread无法使用的问题
问题:使用_beginthread创建多个线程,无法使用WaitForMultipleObjects来
进行同步。
这个问题可以用下面的例子来测试:
view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.#include
04.
__cdecl ThreadProc(void *para)
06.{
07. printf("sub thread startedn");
08. // TODO: Add your thread code here.
09. printf("sub thread finishedn");
10. _endthread(); // 可以省略,隐含会调用。
11.}
12.
main(int argc, char* argv[])
14.{
15. DWORD threadID;
16. HANDLE hThread[10];
17. for(int i =0;i<10;i++)
18. hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);
19.
20. WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //无法同步所有
线程!
21. for(int i = 0;i<10;i++) {
22. CloseHandle(hThread);
23. }
24.}
#include "stdafx.h"
#include
#include
void __cdecl ThreadProc(void *para)
{
printf("sub thread startedn");
// TODO: Add your thread code here.
printf("sub thread finishedn");
_endthread(); // 可以省略,隐含会调用。
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread[10];
for(int i =0;i<10;i++)
hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);
WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //无法同步所有线程!
for(int i = 0;i<10;i++) {
CloseHandle(hThread);
}
}
期望的结果是程序能输出10次的线程创建结束的消息,但是实际运行发现,无
法达到这么多次数。为何?这是因为WaitForMultipleObjects在这里无法正常
工作。原因是:
_endthread()在结束线程的时候,会自动调用CloseHandle关闭内核对象。这就
容易解释了,如果提前关闭了内核对象,WaitForMultipleObjects会返回错误。
那么有没有专门用于_beginthread创建的线程的同步方法呢,就我目前所知,
好象是没有的!要解决这里的问题,可以分别调用WaitForSingleObject来同步,
当然,使用其他一些变相的方法也是可以的,另外,上面的CloseHandle当然就
可以不用再调用了。


发布评论