Windows核心编程--线程

来源:互联网 发布:钮承泽军中乐园知乎 编辑:程序博客网 时间:2024/05/21 17:27

-线程组成
1.线程内核对象。
2.线程栈,用于维护线程执行时所需的所有函数参数和局部变量。

同一进程内线程共享属于进程的资源。

-线程函数
每个线程都须有一个入口点函数,这是线程执行的起点。
主线程的入口点函数:_tmain或_tWinMain。
辅助线程的入口点函数形式:

DWORD WINAPI ThreadFunc(PVOID pvParam){    DWORD dwResult = 0;    ...    return dwResult;}

线程终止运行时,用于线程栈的内存也会被释放,线程内核对象的使用计数也会递减。如果使用计数变为0,线程内核对象会被销毁。
注意:
1.默认下,主线程的入口点函数须命名为main, wmain, WinMain 或 wWinMain。(用/ENTRY:链接器选项可指定一个入口点函数)普通线程函数命名有使用者决定。
2.线程函数必须返回一个值,它会成为该线程的退出代码。
3.函数参数和局部变量,在线程栈上创建。静态变量和全局变量在进程地址空间。

-创建线程

HANDLE CreateThread(PSECURITY_ATTRIBUTES psa,// 默认下,采用链接器指示的 空间和调拨的量// /STACK:[reserve] [,commit]// >0,预定+挑拨所有指定空间。实际预定取两者中较大的DWORD cbStackSize,PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,// 0 立即开始// CREATE_SUSPENDED 暂停DWORD dwCreateFlags,PDWORD pdwThreadID);

写 C/C++代码时,创建线程要使用编译器提供的创建线程函数,后者在内部会调用CreateThread。Microsoft C++编译器中用 _beginthreadex。

-终止线程
1.线程函数返回。
可保证:
线程函数中创建的C++对象,通过其析构函数被销毁。
操作系统正确释放线程栈的内存。
操作系统把线程的退出代码设为线程函数的返回值。
系统递减线程内核对象的使用计数。

2.线程用ExitThread杀死自己。

VOID ExitThread(DWORD dwExitCode);

可保证:
清理操作系统资源。
但:
线程函数中创建的C/C++对象,不会被销毁。

应使用编译器提供的版本,Microsoft C++编译器为_endthreadex。

3.其它线程用TerminateThread。

// 异步调用:立即返回,返回时,可能线程还未终止。BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

被终止运行的线程不会收到通知。

可保证:
操作系统把线程的退出代码设为线程函数的返回值。
系统递减线程内核对象的使用计数。
但不会:
线程函数中创建的C++对象,通过其析构函数被销毁。
操作系统正确释放线程栈的内存。

4.包含线程的进程终止。

-线程终止运行时
1.线程拥有的所有用户对象句柄会被释放。
大多数对象由进程拥有。
但窗口和挂钩属于线程拥有。
线程终止时,系统自动销毁线程创建或安装的任何窗口,并卸载由线程创建或安装的任何挂钩。
2.线程的退出代码从STILL_ACTIVE变为传递的退出代码。
3.线程内核对象变为触发状态。
4.如是进程中最后一个活动线程,则,系统认为进程也终止了。
5.线程内核对象使用计数减1。

// 获得线程退出代码BOOL GetExitCodeThread(HANDLE hThread,PDWORD pdwExitCode);

-线程内幕
1.一旦创建了线程内核对象,系统就分配内存,供线程的堆栈使用。
2.系统将传给CreateThread的pvParam和pfnStartAddr分别写入线程堆栈。
3.每个线程有其自己的一组CPU寄存器,称为线程的上下文。上下文反映了当线程上一次执行时,线程的CPU寄存器的状态。线程的CPU寄存器全部保存在一个CONTEXT结构。CONTEXT结构本身保存在线程内核对象中。
4.
指令指针寄存器
栈指针寄存器
是线程上下文中最重要的两个寄存器。
线程内核对象被初始化时,堆栈指针寄存器被设为pfnStartAddr在线程堆栈的地址。指令指针寄存器被设为RtlUserThreadStart函数的地址。

VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam){    __try    {        ExitThread((pfnStartAddr)(pvParam));    }    __except(UnhandledExceptionFilter(GetExceptionInformation()))    {        ExitProcess(GetExceptionCode());    }}

-C/C++运行库注意

库名称 描述 LibCMt.lib 库的静态链接发行版 LibCMtd.lib 库的静态链接调试版 MSVCRt.lib 导入库,动态链接MSVCR80.dll MSVCRt.lib 导入库,动态链接MSVCR80D.dll MSVCMRt.lib 导入库,托管/本机代码混合 MSVCURt.lib 导入库,编译成纯MSIL代码

1.创建新线程时,用编译器的。
Microsoft C/C++为:_beginthreadex。

unsigned long _beginthreadex(void *security,unsigned stack_size,unsigned (*start_address)(void *),void *arglist,unsigned initflag,unsigned *thrdaddr){_ptiddata ptd;uintptr_t thdl;if((ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL){    goto error_return;}initptd(ptd);ptd->_initaddr = (void*)pfnStartAddr;ptd->_initarg = pvParam;ptd->_thandle = (uintptr_t)(-1);thd1 = (uintptr_t)CreateThread((LPSECURITY_ATTRIBUTES)psa,cbStackSize,_threadstartex,(PVOID)ptd,dwCreateFlags,pdwThreadID);if(thd1 == 0){    goto error_return;}return thd1;error_return:    _free_crt(ptd);    return ((uintptr_t)0L);}static unsigned long WINAPI _threadstartex(void *ptd){TlsSetValue(__tlsindex, ptd);((_ptiddata)ptd)->_tid = GetCurrentThreadId();_callthreadstartex();return 0L;}static void _callthreadstartex(void){_ptiddata ptd;ptd = _getptd();__try{    _endthreadex(((unsigned (WINAPI*) (void*))(((_ptiddata)ptd)->_initaddr))(((_ptiddata)ptd)->_initarg));}__except(_XcptFilter(GetExceptionCode(), GetExceptionInformation())){_exit(GetExceptionCode());}}void __cdecl _endthreadex(unsigned retcode){_ptiddata ptd;ptd = _getptd_noexit();if(ptd){_freeptd(ptd);}ExitThread(retcode);}

1.1.每个线程有自己的 _tiddata内存块,从堆上分配。
1.2.C/C++运行库为每个新线程准备一个独立的数据块,来解决C/C++运行库对多线程的支持。
1.3.执行顺序
_beginthreadex
CreateThread
RtlUserThreadStart
_threadstartex
_callthreadstartex

2.C/C++运行库还围绕特定函数放置了同步对象。如malloc。
3.当模块链接到C/C++运行库的DLL版本时,库在终止时收到DLL_THREAD_DETACH时,会释放已分配的_tiddata数据块。

-了解自己的身份

// 返回 主调进程的进程内核对象的 伪句柄HANDLE GetCurrentProcess();// 返回 主调进程的线程内核对象的 伪句柄HANDLE GetCurrentThread();DWORD GetCurrentProcessId();DWORD GetCurrentThreadId();// 将伪句柄转换为真实的句柄// DuplicateHandle会递增所复制句柄的使用计数DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,x1,x2,x3);DuplicateHandle(GetCurrentProcess(),GetCurrentProcess(),GetCurrentProcess(),&hProcess,x1,x2,x3);

伪句柄:
它们不会在主调进程的句柄表中新建句柄,不会影响进程内核对象或线程内核对象的使用计数。对伪句柄执行CloseHandle,会返回FALSE。可以充当句柄的功能。

把伪句柄以值传递的方式传递给另一个进程或另一个线程,则,在传递后的进程或线程中使用时,它指代的就是所在进程或线程的伪句柄,而不再是原来所在的进程或线程的。

原创粉丝点击