Win32 多线程的创建方法和基本使用
Win32多线程的创建方法主要有:
(2)_beginthread()&&_beginthreadex()
(3)AfxBeginThread()
(4)CWinThread类
(1)CreateThread()
百度百科:http://baike.baidu.com/view/1191444.htm
函数原型:
view plaincopy to clipboardprint?
01.HANDLE 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.
04.DWORD WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread started\n");
07. printf("sub thread finished\n");
08. return 0;
09.}
10.
11.int 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 started\n");
printf("sub thread finished\n");
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,用于同步一组内核对象。(参考http://msdn.microsoft.com/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.
04.DWORD WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread started\n");
07. // TODO: Add your thread code here.
08. printf("sub thread finished\n");
09. return 0;
10.}
11.
12.int 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 started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
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()
百度百科:http://baike.baidu.com/view/3029167.htm
MSDN:http://msdn.microsoft.com/zh-cn/library/kdzttdcb.aspx
函数原型:
view plaincopy to clipboardprint?
01.uintptr_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?
#include "stdafx.h"
#include
#include
void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_endthread(); // 可以省略,隐含会调用。
}
int main(int argc, char* argv[])
{
HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
}
#include "stdafx.h"
#include
#include
void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_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 Libcmt.lib, 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.”,简单翻译就是说,对于链接Libcmt.lib的可执行程序,不要使用Win32的线程退出函数(ExitThread),这会阻止运行时系统回收分配的资源,应该使用_endthread,它能回收分配的线程资源然后调用ExitThread。这个问题看似没有提到CreateThread(),但是其实有关,这就是经常看到有些资料上坚决的说到”不要使用CreateThread创建线程,否则会内存泄漏“的来源了。
问题引出:CreateThread的内存泄漏问题(CreateThread和_beginthread的区别)
Related Topics:http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html http://www.cnblogs.com/whiteyun/archive/2011/06/02/2067742.html ....
1. _beginthread也是通过CreateThread来创建线程的,只是_beginthread对其进行了一些封装,将相关”资源“通过线程的本地存储(TLS)传递给了线程函数的参数,然后在调用_endthread的时候,会将这些保存的资源进行释放。
2. 并不是所有的使用CreateThread的情况都会有内存泄漏。看了很多人的文章,只有http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html的分析是最清晰的,我已经转到http://dl.dbank.com/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.
05.void __cdecl ThreadProc(void *para)
06.{
07. printf("sub thread started\n");
08. // TODO: Add your thread code here.
09. printf("sub thread finished\n");
10. _endthread(); // 可以省略,隐含会调用。
11.}
12.
13.int 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 started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_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当然就可以不用再调用了。
总结:看来_beginthread也不是那么好用。:)
Win32 多线程的创建方法和基本使用的更多相关文章
- Java多线程的创建方法
Java 线程类也是一个 object 类,它的实例都继承自java.lang.Thread 或其子类. 可以用如下方式用 java 中创建一个线程,执行该线程可以调用该线程的 start()方法: ...
- win32多线程: 线程创建与结束等待
#include<Windows.h> #include<iostream> using namespace std; /*1.在启动一个线程之前,必须为线程编写一个全局的线程 ...
- Win32多线程编程(3) — 线程同步与通信
一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...
- 深入浅出Win32多线程程序设计之基本概念
一.深入浅出Win32多线程程序设计之基本概念[转] 引言 从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最优秀的程序员也只能通过驻留内存的方式实现所谓 ...
- 多线程学习:win32多线程编程基本概念(转)
一.定义: 1.进程和线程的区别 进程:是程序的执行过程,具有动态性,即运行的程序就叫进程,不运行就叫程序 ,每个进程包含一到多个线程.线程:系统中的最小执行单元,同一进程中有多个线程,线程可以共享资 ...
- Java Native Interface 五 JNI里的多线程与JNI方法的注册
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...
- iOS开发多线程篇—创建线程
iOS开发多线程篇—创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] in ...
- Win32多线程编程(1) — 基础概念篇
内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...
- win32多线程-重写消息循环
最近正在学习<win32多线程程序设计>,这是其中一段重写消息循环的代码事例,以后可能用的上. while (!quit || gNumPrinting > 0) { // Wait ...
随机推荐
- jQuery中的$.extend方法总结
原文见:jQuery.extend()函数详解 Jquery的扩展方法extend是我们在写插件的过程中常用的方法,但是经常容易搞不清楚以下两个写法的关系: 1.$.extend(dest,src1, ...
- jdbc 处理mysql procedure返回的多个结果集
1:测试数据库表user mysql> desc user$$ +-------+-------------+------+-----+---------+----------------+ | ...
- jquery.sortable.js源代码解读
/* * HTML5 Sortable jQuery Plugin * http://farhadi.ir/projects/html5sortable * * Copyright 2012, Ali ...
- USB_scsi 之旅
现在总结一下scsi,scsi协议有很多,所以只总结这次在usb mass storage里面用到的协议,主要包括inquiry,format , read write等等命令. 下面会一个一个总结. ...
- qt 多线程之间通讯
问题描述:界面线程MainApp为主线程,工作线程MyThread为一子线程,从工作线程向主线程传递字符串用于在主线程中显示. Qt的信号与槽机制可以将任何继承自QObject类的对象捆绑在一起,使不 ...
- 【Xamarin挖墙脚系列:Mono项目的图标为啥叫Mono】
因为发起人大Boss :Miguel de lcaza 是西班牙人,喜欢猴子.................就跟Hadoop的创始人的闺女喜欢大象一样...................... 历 ...
- [置顶] SPL讲解(6)--Condition篇
SmartPersistenceLayer 2.0 之 Condition篇 原理 强大的Condition功能是SPL的一个特性,可以使用Condition完成绝大部分的条件定义,使用 ...
- shell字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号.单双引号的区别跟PHP类似. 单引号 str='this ...
- java.lang.UnsatisfiedLinkError: no XXX in java.library.path
其中涉及的测试源码如下: For those who didn't install Javawith default settings, a systematic way for solving JN ...
- UGUI Button控件
今天一起来学习下Button控件, Button控件其实是由Text,Button,Image组件形成的. 这里就简单介绍下Button组件 Interactable: 代表该组件是否进行交互, 我们 ...