关于线程的执行和退出

简介:

线程由两部分构成:

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

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

 

我们必需要知道一个事实 ----- 进程( 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 退出整个进程。

作者:码瘾少年·麒麟子 
出处:http://www.cnblogs.com/geniusalex/ 
蛮牛专栏:麒麟子 
简介:09年入行,喜欢游戏和编程,对3D游戏和引擎尤其感兴趣。 
版权声明:本文版权归作者和博客园共有,欢迎转载。转载必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载:http://www.cnblogs.com/geniusalex/archive/2010/07/02/1940486.html

目录
相关文章
|
8月前
|
Java
Java 中通知线程退出的理解
Java 中通知线程退出的理解
41 0
|
API
如何让一个线程“优雅”地退出
如何让一个线程“优雅”地退出
135 0
线程的创建等待及退出 代码源码举例
线程的创建等待及退出 代码源码举例
46 0
|
存储 物联网 Linux
Pthread_exit 线程退出|学习笔记
快速学习 Pthread_exit 线程退出
184 0
|
Java C++
Java线程监听,意外退出线程后自动重启
Java线程监听,意外退出线程后自动重启   某日,天朗气清,回公司,未到9点,刷微博,顿觉问题泛滥,惊恐万分!   前一天写了一个微博爬行程序,主要工作原理就是每隔2分钟爬行一次微博,获取某N个关注朋友微博数量,然后将其保存起来,2分钟之后再次爬行,再取 其微博数量,与2分钟前保存的微博数量比较,如果数量增加,说明该好友在此2分钟之内发布微博,如果数量减少,则是删除微博。
1301 0
|
程序员 C++
C/C++四种退出线程的方法
退出线程可以有四种方法: 1.线程函数的return返回(最好这样):   其中用线程函数的return返回, 而终止线程是最安全的, 在线程函数return返回后, 会清理函数内申请的类对象, 即调用这些对象的析构函数.
1071 0

热门文章

最新文章