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++运行库注意
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。可以充当句柄的功能。
把伪句柄以值传递的方式传递给另一个进程或另一个线程,则,在传递后的进程或线程中使用时,它指代的就是所在进程或线程的伪句柄,而不再是原来所在的进程或线程的。
- windows核心编程--线程
- windows 核心编程 线程
- windows核心编程--线程
- windows核心编程--线程
- Windows核心编程--线程
- windows核心编程--线程高级
- windows核心编程--线程池
- windows核心编程--线程高级
- windows核心编程--线程池
- Windows核心编程:线程基础
- Windows核心编程:线程调度
- 线程基础----Windows核心编程
- windows核心编程--线程高级
- Windows核心编程-----线程池
- windows核心编程--线程高级
- Windows核心编程 -- 线程基础
- windows核心编程-线程退出
- Windows核心编程之线程
- 【BZOJ4094】 【Usaco2013 Dec】Optimal Milking(权限题)
- 以非root身份安装Python的Module或者Package以及pip安装指定路径
- 【BZOJ4094】【Usaco2013 Dec】Optimal Milking(线段树)
- Java 基础(5)—— 普通代码块、构造代码块、静态代码块
- tensorflow 安装目录在哪里?
- Windows核心编程--线程
- 调试时不用在cmd中输入命令参数,直接在属性页中操作
- java.io.Serializable 序列化
- MAC 下用 pip 安装时出现 OSError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/
- 读Zepto源码之Fx模块
- 【BZOJ3107】【cqoi2013】二进制a+b
- 043 Tayler泰勒公式证明
- 【BZOJ4282】慎二的随机数列
- poj2409 Let it Bead(置换)