Windows Via C/C++:线程实现细节
我们已经了解如何定义线程入口点函数、调用系统API创建执行指定函数的线程。本节将揭示这一切在系统内部是如何完成的。
图6-1描述了线程创建并完成初始化后的状态。调用CreateThread会使系统产生一个线程内核对象,其引用计数(Usage count)被初始化为2(创建线程的进程和线程本身都引用了该内核对象),其它属性也完成了初始化:暂停标置(Suspend count)被设置为1,线程退出码(Exit code)被设置为STILL_ACTIVE,内核对象状态被置为nonsignaled(Signaled)。
内核对象创建完成后,系统在当前进程中为新线程的线程栈分配内存,并在线程栈的高位写入两个值。第1个指是CreateThread函数的pvParam参数,然后是pfnStartAddr参数。
每个线程有自己的CPU寄存器组,被称为线程上下文(Context),线程的上下文反映了线程最后一次执行时其CPU寄存器的状态。WinNT.h中定义了CONTEXT结构对应线程的CPU寄存器组,线程的CONTEXT实例保存在其内核对象中。
线程上下文中最重要的两个寄存器是指令指针寄存器(Instruction pointer)和栈指针寄存器(Stack pointer)。由于线程是运行在进程地址空间内的,因此其栈中的地址就是进程地址空间中的地址。线程内核对象初始化时,其CONTEXT结构中的栈指针寄存器内容被设置为pfnStartAddr在线程栈中的地址,指令指针寄存器内容被设置为名为RtlUserThreadStart的函数的地址,该函数在NTDLL.dll中定义,基本框架如下所示:
VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
__try {
ExitThread((pfnStartAddr)(pvParam));
}
__except(UnhandledExceptionFilter(GetExceptionInformation())) {
ExitProcess(GetExceptionCode());
}
// NOTE: We never get here.
}
线程初始化完成后,系统会检查CreateThread是否传递了CREATE_SUSPENDED参数,如果没有的话,系统会把线程内核对象的暂停计数设置为0并马上调度线程,然后将线程上下文中的值加载到CPU的寄存器组中,由于线程指令指针寄存器指向RtlUserThreadStart,因此线程将以RtlUserThreadStart开始执行,RtlUserThreadStart又调用了CreateThread为线程设置的入口点函数pfnStartAddr,并在pfnStartAddr返回时调用ExitThread退出线程。要注意假如在pfnStartAddr执行时发生了未处理的异常,RtlUserThreadStart中的结构化异常处理框架将执行ExitProcess,导致整个进程的退出。
相关文档:
代码:
#include <iostream>
using namespace std;
class Clock
{
int hour, minute, second;
public:
Clock(int h, int m, int s) //构造函数定义 ,无返回值类型
{
if(s<0) second=0;
if (s& ......
由于程序运行时占用的内存过大,所以想办法给程序瘦身。
在调试中发现结构体占用的size竟然和预想的不一样,原来……
看看下面讲的吧,肯定会不枉此看哦!
1,比如:
struct{
short a1;
short a2;
short a3;
}A;
struct{
long a1;
short a2;
}B;
sizeof(A)=6, sizeof(B)=8,为什么?
注:sizeof(sho ......
一家之言,欢迎拍砖哈。
1、可以考虑先学习C.
大多数时候,我们学习语言的目的,不是为了成为一个语言专家,而是希望成为一个解决问题的专家。做一个有用的程序员,做一个赚钱的程序员。我们的价值,将体现在客户价值上,而不是语言写得好不好看。
C++是C的一个面向对象的解释,C++为C扩充了大规模工程应 ......
int main(int argc,char *argv[])
argc(argument count):参数的个数;
argv(argument value):参数值
argv[0] :文件名
argv[1]:第一个参数,argv[2];第二个参数,以此类推。
编译C
1 单源程序到可执行程序
编译 & ......