您的位置:首页 > 其它

关于线程的执行和退出

2013-05-10 00:11 106 查看
线程由两部分构成:

线程内核对象:操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。

线程堆栈:它用于维护线程在执行代码时需要的所有函数参数和局部变量。

 

我们必需要知道一个事实
-----
进程(
WINDOWS
中)是不能被调度的。通常所说的调度,都是对线程而言的。进程仅仅是线程的容器,是系统统分配资源的单位。
这样,线程自身不会分配资源。同一进程中的多个线程共同使用它们父进程的资源。

 

一个进程至少需一个线程,如果一个进程中不存在线程(所有线程都退出)。则系统认为这个进程没有存在的必要,于是便会撤消这个进程,并释放他占用的资源。

 


VC
环境中,我们可以调用
CreatThread
来创建一个线程。关于用法请查
MSDN

我们应该主要关注这个
API
的调用,操作系统会干哪些事情。而不是仅仅会使用这个
API


 

当程序启动的时候,系统会创建一个进程,进而会为这个进程创建一个主线程。主线程即是一个程序的入口。
C/C++
运行期库会初始化全局的
C/C++
变量,然后调用入口点函数(如
main
)。然后初始化线程堆栈,创建临时变量等。

 

当线程结束时会按以下操作执行。

1、     

在线程函数中创建的所有
C++
对象均将通过它们的撤消函数正确地撤消。

2、     

操作系统将正确地释放线程堆栈使用的内存。

3、     

系统将线程退出代码设置为线程函数的返回值。

4、     

系统将递减线程内核对象的引用计数。

 

因此,正确的线程退出方式是必不可少的。
最好的退出线程的方法是让线程函数返回,这样
C/C++
运行期库便能正确地撤消
C/C++
对象。
值一说的是,不管线程怎么退出,当一个程序结束时,系统总是回清除他使用了的系统资源,如内核对象等。但
C/C+=
运行期库申请的资源则不会被释放。

 


ExitThread
等函数,需要三思而用。

 

众所周知,创建线程的时候,必不可少的两个参数就是线程入口函数和函数参数。那这两个是怎么工作的呢。请看如下分析。

 

首先要知道,每个线程都有自己的一组
CPU
寄存器。这组寄存器的所有信息就是我们所说的线程上下文。当系统进行时间片轮转执行线程的时候,会将前一个线程的所有寄存器值保存,然后将下一个需要执行的线程的寄存器值装入
CPU
寄存器,进而执行。重复这样的操作,就达到了多线程执行的效果。当然,实际情况是很复杂的。需要许多的判断,在多处理器计算机中,还需要考虑线程的亲缘性等。

 

话不多说,回头来看这个线程函数的执行方式。

当一个线程被创建时,系统便会创建线程的内核对象。并分配线程堆栈需要的内存。这个内存是从进程的地址空间分配而来的,因为我们知道,线程不持有资源。当一切都做好后,便是填写数据了。

 

系统首先会把线程的参数和入口地址压入线程堆栈。
注意,是先压的参数,再压的入口地址。这样入口地址是在栈顶。此时
SP
的值即为函数入口地址。
而将
IP
设置为另一个函数。它叫
void BaseThreadStart();
很神奇吧,为什么
IP
并不是线程的入口函数地址呢。
我们直接可以猜到,
void BaseThreadStart();
所做的工作中,会调用到我们的线程入口函数。接下来我们看看
void BaseThreadStart();
函数干了些什么。

void BaseThreadStart(PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam)

{

  __try{

Exithread((pfnStartAddr)(pvParam));

}

__except(UnhandedExceptionFilter(GetExceptionInformation()){

ExitProcess(GetExceptionCode());

}

}

 

还记得我们压栈的时候是先压的参数再压的线程函数入口地址么。这就对了,上面即是这样的情况。
可以看出,
BaseThreadStart
函数不会马上返回,他会等待线程结束后返回。由于线程和进程共用的进程内存空间,可以知道。如果线程函数没有退出
BaseThreadStart
就返回,可以肯定的会引发访问违规。因为线程未退出时,线程堆栈并未清除。
BaseThreadStart
返回时,从堆栈上得到的返回地址是一个不可预测的值。
进程在初始化时也会是类似执行方式。因为进程执行时,启动的是一个主线程,而不是由进程本身来执行代码。

 

最后说明,当新线程执行
BaseThreadStart
函数时,将会出现如下情况:

1、     

在线程函数中建立一个
SHE
,这样,在线程执行时产生的任何异常情况都将会得到系统的某种默认处理。

2、     

系统调用线程函数,并将你传递的参数传递给它。

3、     

当线程函数返回时,
BaseThreadStart
调用
Exithread
,并将线程函数的返回值传递给它。该线程内核对象的使用计数减
1
,线程停止运行。

4、     

如果线程产生一个没有处理的异常条件,由
BaseThreadStart
建立的
SHE
将负责处理该异常。由上面可以看出,它调用
ExitProcess
退出整个进程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: