Windows Via C/C++ 读书笔记 3

Windows Via C/C++ 读书笔记 

1. Job

JOB,翻译成工作或者任务。JOB是管理多个进程的集合体。如果你需要一次关闭多个进程,并且要在所有进程退出后得到通知,那么可以使用JOB这种对象。

1.1. Job的使用流程

1. 创建JOB或查找一个已有的JOB

2. 把进程加入到JOB

3. 关闭JOB

4. 等待JOB结束(JOB结束后会处于Signaled状态,因此可以用WaitForSingleObject 等待)

2. 线程

线程含有两个东西:

一个内核对象,用于操作系统管理,含有线程的静态信息。和进程内核对象类似。

线程这个东西用了太久了,就不废话了。拣点以前没注意的死角说说。

2.1. 线程栈(Thread`s Stack)。

线程栈是有大小的,默认是1M。超过的时候会有"overflow"异常,但是操作系统会捕捉异常,给栈更多的空间,使栈能动态增长。

创建线程的时候可以通过参数设置栈大小,也可以在link选项/STACK中设置,最终取两者中大的一个。 

2.2. 线程结束

和进程结束太类似了。有点要注意:如果用"TerminateThread" 杀死另外一个线程,操作系统是不会销毁它的栈,直到这个进程结束。

"GetExitCodeThread"可以得到线程的退出码,如果线程没有退出,那么这个值是"STILL_ACTIVE" 

2.3. 线程内部

线程内核对象:

SP(Stack Pointer)指向栈的头,栈顶是线程函数的参数,接着是执行代码的起始地址。

IP(Instruction Pointer) 指向函数"RtluserThreadStart",该函数在"NTDLL.dll"中导出。

还保留了线程执行时CPU寄存器的状态,用于线程切换的时候,可以恢复切换前的执行状态。

VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {

   __try {

      ExitThread((pfnStartAddr)(pvParam));

   }

   __except(UnhandledExceptionFilter(GetExceptionInformation())) {

      ExitProcess(GetExceptionCode());

   }

   // NOTE: We never get here.

}

RtlUserThreadStart原型

线程执行肯定会在RtlUserThreadStart中结束,正常结束调用ExitThread(线程结束),异常调用ExitProcess(进程结束),并且会弹出窗口报错。

该函数的第一个参数,函数地址参数是操作系统显示写入线程stack中,使该函数看起来像是被别人调用,实际上它是起始执行函数。

2.4. _beginthreadex & _endthreadex

2.4.1. _beginthreadex代替CreateThread

多线程的时候,有些全局变量的访问会冲突。如:errno, _doserrno, strtok_wcstok, strerror, _strerrortmpnam, tmpfile, asctime_wasctime, gmtime, _ecvt, and _fcvt

为了让各个线程有自己的变量,用_beginthreadex代替CreateThread函数。

_beginthreadex函数中会给每个线程创建一个变量块(类型为_tiddata,这个结构存了这些errno什么的,还有线程函数的入口地址)

下面都是伪代码,描述函数主要过程:

_beginthreadex 

{

......

分配一块内存,结构为_tiddata,变量名为pid;

创建一个线程(CreateThread),函数为_threadstartex,把pid作为参数传给这个函数;

......

}

_threadstartex

{

......

pidTSL关联,变成与线程相关的变量

Try{

执行线程函数,线程函数地址存在pid

执行_endthreadex结束线程,把线程函数执行退出结果作为_endthreadex的参数。

}catch

{

.......

}

......

}

_endthreadex

{

释放TSL变量pid

调用ExitThread退出线程

}

如过用CreateThread代替_beginthreadex,会有什么问题呢?

1.操作系统会在第一次使用pid的时候检查是否已经分配,如果没有会创建一个新的并关联。但是因为没有调用_endthreadex,这个变量不会被释放直到进程退出。

2.原文是First, if the thread uses the C/C++ run-time library's signal function, the entire process terminates because the structured exception handling frame has not been prepared.

这块还不清楚,在_beginthreadextry块会处理一些异常,如果用CreateThread这种异常没有捕捉会使整个进程退出。

2.5. 不要使用_beginthread 和 _endthread

因为这两个函数的参数少,因此功能会比ex版本的函数功能弱,比如不能带安全参数,不能带suspend标志,不能返回线程号。_endthread只能使退出码硬编码为0

_endthread会关闭线程句柄,因此线程结束后线程句柄不能访问,而ex版本的不会,例如下面这段代码,线程句柄在_beginthread后可能已经关闭了,后面的访问会出错。

DWORD dwExitCode;

HANDLE hThread = _beginthread(...);

GetExitCodeThread(hThread, &dwExitCode); //error!

CloseHandle(hThread);

2.6. DuplicateHandle产生真实句柄

The GetCurrentThread function retrieves a pseudo handle for the current thread.

因此需要用函数转换一下,否则不能被其它函数使用,也不能传递给其它线程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值