关于线程的执行和退出

线程由两部分构成:

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

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

 

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

时间: 2024-11-03 12:06:28

关于线程的执行和退出的相关文章

多线程-创建线程过多会出现线程不执行问题?

问题描述 创建线程过多会出现线程不执行问题? #include "stdafx.h" #include #include #include #include using namespace std; DWORD CALLBACK ThreadFun_02(LPVOID lp); bool PrintLog(const char * pString); CRITICAL_SECTION g_Cs; int g_iTickets = 20; int main() { InitializeC

python 线程的暂停, 恢复, 退出详解及实例_python

python 线程 暂停, 恢复, 退出 我们都知道python中可以是threading模块实现多线程, 但是模块并没有提供暂停, 恢复和停止线程的方法, 一旦线程对象调用start方法后, 只能等到对应的方法函数运行完毕. 也就是说一旦start后, 线程就属于失控状态. 不过, 我们可以自己实现这些. 一般的方法就是循环地判断一个标志位, 一旦标志位到达到预定的值, 就退出循环. 这样就能做到退出线程了. 但暂停和恢复线程就有点难了, 我一直也不清除有什么好的方法, 直到我看到thread

谁有多线程代码!!我想实现10个线程同时执行一个方法!

问题描述 我想10个线程同时执行一个方法,但是每个方法传入的参数是不一样的!我在网上找了些代码,但是不行,造成线程混乱,谁能教教我啊!!想要实现的是:10个线程同时去登陆网站,然后采集东西.当然我也有10个用户名.10个线程每个线程对应一个用户. 解决方案 解决方案二:分太少了.不然老夫贴出来解决方案三:ThreadPool.QueueUserWorkItem();解决方案四:给你个多线程的例子privatevoidbtnDataUp_Click(objectsender,RoutedEvent

C程序fork进程导致PHP执行不退出

/********************************************************************* * C程序fork进程导致PHP执行不退出 * 说明: * 由于测试的GPIO程序需要持续运行,而主进程需要处理其他事务但退出时 * 由于子线程未结束导致PHP系统调用函数不退出,解决办法是双重fork(第一次 * fork产生子进程用于kill掉让第二次fork出的子进程变成孤儿进程),并将最终 * 的子进程转换为守护进程,从而不影响PHP获取主进程数据

mfc循环创建的多线程A去调用了另外一个线程B,其中A线程出问题要退出。

问题描述 mfc循环创建的多线程A去调用了另外一个线程B,其中A线程出问题要退出. mfc循环创建的多线程A去调用了另外一个线程B,其中A的一个线程出问题要退出.B线程怎么也终止了 怎么办?用的是下面这个. // 资源释放结束,可退出线程并析构类 pMg->m_ExitThread.SetEvent();

线程同步-linux可以用互斥锁控制多个线程的执行顺序吗?如何实现?

问题描述 linux可以用互斥锁控制多个线程的执行顺序吗?如何实现? 假设有三个线程:1.2.3,各自打印A,B,C.是否可以只用互斥锁就实现"ACBCACBC--"的打印输出?(不使用其他的线程同步方法) 解决方案 这种用自旋锁更好呀,而且实现更简单,顺序执行即可.

c语言 线程-求帮助!C语言有个输出线程无法执行

问题描述 求帮助!C语言有个输出线程无法执行 /*创建线程1:读入请求 */ DWORD ThreadID = 1; //创建线程(对应于函数getInput()),用于接收电梯输入: HANDLE hRead =CreateThread(NULL0(LPTHREAD_START_ROUTINE)getInputNULL0&ThreadID); DWORD ThreadID2=2;//输出线程 HANDLE hRead2=CreateThread(NULL0(LPTHREAD_START_ROU

MFC判断线程是否执行过,有没有更好的思路呢?

问题描述 MFC判断线程是否执行过,有没有更好的思路呢? MFC判断线程是否执行过.我的思路是使用数组来记录,可是数组的长度是很难更改的,有没有更好的思路呢? 解决方案 用stl vector集合来记录就是了.用push_back 解决方案二: 那不用数组用链表? 或者在主线程设置一个变量,附加线程运行的时候sendmessage改变变量,通过这个变量来判断线程是否执行过.

捕获Java线程池执行任务抛出的异常

捕获Java线程池执行任务抛出的异常Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { public abstract void run(); } 那么如果 run() 方法中抛出了RuntimeException,将会怎么处理了? 通常java.lang.Thread对象运行设置一个默认的异常处理方法: java.lang.Thread.setDefaultUncaughtExceptionH