Windows核心编程之线程创建
来源:互联网 发布:淘宝详情页怎么加链接 编辑:程序博客网 时间:2024/05/22 15:13
一、线程创建
Windows线程在创建时会首先创建一个线程内核对象,它是一个较小的数据结构,操作系统通过它来管理线程。新线程可以访问进程内核对象的所有句柄、进程中的所有内存及同一进程中其它线程的栈。
创建有以下几种方式,分别说明
- CreateThread(...) (操作系统提供的API,尽量不要使用)
- _beginthread(...)
- _beginthreadex(...)
- AfxBeginThread(...) (MFC提供的接口)
首先声明一个线程函数,原型为:
DWORD FunThread(LPVOID pParam);
1. CreateThread()
该函数为操作系统提供,原型如下:
HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes , _In_ SIZE_T dwStackSize , _In_ LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD lpThreadId );
说明:
HeaderLibraryDllWinBase.hKernel32.libKernel32.dll
参数:
lpThreadAttributes:指向SECURITY_ATTRIBUTES结构体的指针,记录线程的安全描述。决定子进程能否继承到返回的句柄,如果为NULL,则采用默认安全级别(THREAD_PRIORITY_NORMAL),同时返回句柄不能继承
dwStackSize:指定线程栈大小,当为0时,表示栈使用默认大小
lpStartAddress:线程函数指针
lpParameter:线程函数参数
dwCreationFlags:为0:表示线程创建后立即运行;为CREATE_SUSPEND:创建后挂起,此时可修改线程属性,通过ResumeThread唤醒;
lpThreadId:一个指向threadID的指针,若对线程ID关注,则传值,否则置NULL
返回值:
创建线程的句柄;
若创建失败,则返回NULL,可用GetLastError()捕获错误;
MFC中也提供了CreateThread函数,它是CWinThread类的一个方法,如下
BOOL CreateThread( DWORD dwCreateFlags = 0, UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
参数含义与返回值含义一致,它的调用方式是:
CWinThread thread1;thread1.CreateThread();
需要说明的是dwCreateFlags传值为CREATE_SUSPEND时, 要通过CWinThread::ResumeThread来唤醒
2. _beginthread(), _beginthreadex()
原型:
unsigned long _beginthread(
void( __cdecl *start_address )( void * ),
unsigned stack_size, void *arglist
);
unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
参数与上面CreateThread含义相同,不在赘述;
二者比较:
1. _beginthread中线程函数调用为_cdecl,且无返回值; _beginthreadex为_stdcall,有返回值;
2. _beginthreadex中initflag相当于CreateThread中的dwCreationFlags,thrdaddr相当于lpThreadId
3.在实现上_beginthreadex控制了一个_tiddata的线程数据块,里面存放了线程函数地址、参数的很多属性,之后再间接调用CreateThread(...);
4._beginthread则参数较少;
3. AfxBeginThread()
MFC提供的接口提供了二种不同类型线程的生成,即工作者线程和用户界面线程;可以简单理解用户界面线程包含用户界面,它有自己的消息队列,工作者线程用于计算等;
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, //线程函数指针,函数原型为UINT _cdecl fnThread(LPVOID pParam); LPVOID pParam, //线程函数参数 int nPriority = THREAD_PRIORITY_NORMAL, //优先级,SetThreadPriority UINT nStackSize = 0, //栈大小,单位是bytes,为0时表示按默认大小 DWORD dwCreateFlags = 0, //CREATE_SUSPENDED:创建后挂起; 0:创建后立即运行 LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //指向SECURITY_ATTRIBUTES结构的指针,为Null时表示默认安全属性); //创建一个工作者线程CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, //指向界面类指针,继承自CWinThread int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ); //创建一个用户界面线程
说明:
HeaderAfxwin.h
4. 比较
1. _beginthread与_beginthreadex
- 在实现上_beginthreadex控制了一个_tiddata的线程数据块,里面存放了线程函数地址、参数的很多属性,之后再间接调用CreateThread(...);
- _beginthread则参数较少,有局限性;
2. AfxBeginThread与mfc的CreateThread
- AfxBeginThread一步创建,之后线程立即运行
- CWinThread::CreateThread二步创建,但它保存了线程对象,可以在连续的线程创建与运行完成结束之间再使用(Use CreateThread if you want to reuse the thread object between successive creation and termination of thread executions)
二、注意事项
1.在C++多线程编程中,尽量使用_beginthreadex及_endthreadex,而不是其它接口。
不使用_beginthread原因:
(1)_beginthread函数参数不够多,某些要求达不到,
不使用_endthread原因:
(1)_endthread函数也是无参的,即线程的退出代码会被硬编码为0;
(2)该函数在调用ExitThread前,会调用CloseHandle,并传入新线程的句柄。类似下面代码会有错误
DWORD dwExitCode;HANDLE hThread = _beginthreadex(...);GetExitCodeThread(hThread, &dwExitCode);CloseHandle(hThread);
不使用CreateThread函数原因:
(1)标准C/C++运行库最初并不是为多线程程序而设计的(标准的C运行时库出现在操作系统对线程支持之前),而CreateThread是操作系统接口,调用它时系统不知道是C/C++来调用的,因此为了保证C/C++程序正常运行,要创建一个数据结构与运行库的每个线程关联,_beginthreadex就实现了这样的功能。换言之,在C/C++中用CreateThread创建线程是极度不安全的。
不使用ExitThread函数原因:
(1)操作系统相关资源释放;但象C++类并未析构,造成内存泄露;这里如果用_beginthreadex建立线程,而用ExitThread或者_endthread来释放线程,则线程放在堆上的线程数据块_tiddata也未释放,内存泄露;
2.C/C++编程中使用CreateThread会发生什么
当线程调用一个需要线程数据块_tiddata的运行库函数时,系统会首先通过线程局部存储(TLS,见下节)来找到线程数据块,若为NULL,C/C++运行库会主调线程分配并初始化一个_tiddata块并与线程关联。但若使用C/C++运行库的signal函数,则整个进程都会终止(因结构化异常处理帧SEH未就绪,RtlUserThreadStart会直接调用ExitProcess来结束进程);此外,若不通过_endthreadex来结束线程,线程数据块_tiddata不会释放,造成内存泄露。
- Windows核心编程之线程创建
- Windows核心编程之线程
- windows核心编程之线程
- windows核心编程-创建线程CreateThread
- Windows 核心编程之线程局部存储
- windows核心编程之进程&线程
- Windows核心编程之线程内幕
- Windows核心编程之线程终结
- 《Windows核心编程》之“线程栈”
- 《Windows核心编程》之“线程基础”
- 《Windows核心编程》之“线程池”
- windows核心编程之线程补充
- windows核心编程--线程
- windows 核心编程 线程
- windows核心编程--线程
- windows核心编程--线程
- Windows核心编程--线程
- 《windows核心编程》读后编码--创建线程
- 深入理解redis_memcached失效原理
- iOS Swift&OC 模仿主流App 实现滑动视图隐藏导航栏
- Qt 错误"new types may not be defined in a return type" error
- android,闹钟定时功能,实现过程
- 51nod 1232:完美数
- Windows核心编程之线程创建
- HttpURLConnection +HttpClient
- 三门问题的误区
- 无法对视图创建索引,因为该视图未绑定到架构 SQLServer
- MATLAB相关函数
- Android adb常见问题整理
- 【BZOJ4513】【Sdoi2016】储能表
- 通过.txt/.excel提供的数据对完整图像进行局部抠图
- Windows内核编程笔记(一)