A
线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其它线程共享该进程所拥有的全部资源。线程可以创建和撤销线程,从而实现程序的并发执行。一般,线程具有就绪、运行和阻塞三种基本状态。
线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。
进程拥有这许多共性的同时,还拥有自己的个性。有了这些个性,线程才能实现并发性。这些个性包括:
1.线程ID
每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标
识线程。
2.寄存器组的值
由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线
由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线
程切换到另一个线程上
时,必须将原有的线程的寄存器集合的状态保存,以便
将来该线程在被重新切换到时能得以恢复。
3.线程的堆栈
堆栈是保证线程独立运行所必须的。
线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程
堆栈是保证线程独立运行所必须的。
线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程
必须拥有自己的函数堆栈,
使得函数调用可以正常执行,不受其他线程的影
响。
4.错误返回码
由于同一个进程中有很多个线程在同时运行,可能某个线程进行系统调用
后设置了errno值,而在该
线程还没有处理这个错误,另外一个线程就在此时
被调度器投入运行,这样错误值就有可能被修改。
所以,不同的线程应该拥有自己的错误返回码变量。
所以,不同的线程应该拥有自己的错误返回码变量。
5.线程的信号屏蔽码
由于每个线程所感兴趣的信号不同,所以线程的信号屏蔽码应该由线程自己管理。但所有的线程都共享同样的信号处理器。
6.线程的优先级
由于线程需要像进程那样能够被调度,那么就必须要有可供调度使用的参数,这个参数就是线程的优先级。
涉及多线程程序涉及的时候经常会出现一些令人难以思议的事情,用堆和栈分配一个变量可能在以后的执行中产生意想不到的结果,而这个结果的表现就是内存的非法被访问,导致内存的内容被更改。
理解这个现象的两个基本概念是:在一个进程的线程共享堆区,而进程中的线程各自维持自己堆栈。
理解这个现象的两个基本概念是:在一个进程的线程共享堆区,而进程中的线程各自维持自己堆栈。
在 windows 等平台上,不同线程缺省使用同一个堆,所以用 C 的 malloc (或者 windows 的 GlobalAlloc)分配内存的时候是使用了同步保护的。如果没有同步保护,在两个线程同时执行内存操作的时候会产生竞争条件,可能导致堆内内存管理混乱。比如两个线程分配了统一块内存地址,空闲链表指针错误等。
Symbian 的线程一般使用独立的堆空间。这样每个线程可以直接在自己的堆里分配和释放,可以减少同步所引入的开销。当线程退出的时候,系统直接回收线程的堆空间,线程内没有释放的内存空间也不会造成进程内的内存泄漏。
但是两个线程使用共用堆的时候,就必须用 critical section 或者 mutex 进行同步保护。否则程序崩溃时早晚的事。如果你的线程需要在共用堆上无规则的分配和释放任何数量和类型的对象,可以定制一个自己的 allcator,在 allocator 内部使用同步保护。线程直接使用这个 allocator 分配内存就可以了。这相当于实现自己的 malloc,free。但是更建议你重新审查一下自己的系统,因为这种情况大多数是不必要的。经过良好的设计,线程的本地堆应该能够满足大多数对象的需求。如果有某一类对象需要在共享堆上创建和共享,这种需求是比较合理的,可以在这个类的 new 和 delete 上实现共享保护。
Symbian 的线程一般使用独立的堆空间。这样每个线程可以直接在自己的堆里分配和释放,可以减少同步所引入的开销。当线程退出的时候,系统直接回收线程的堆空间,线程内没有释放的内存空间也不会造成进程内的内存泄漏。
但是两个线程使用共用堆的时候,就必须用 critical section 或者 mutex 进行同步保护。否则程序崩溃时早晚的事。如果你的线程需要在共用堆上无规则的分配和释放任何数量和类型的对象,可以定制一个自己的 allcator,在 allocator 内部使用同步保护。线程直接使用这个 allocator 分配内存就可以了。这相当于实现自己的 malloc,free。但是更建议你重新审查一下自己的系统,因为这种情况大多数是不必要的。经过良好的设计,线程的本地堆应该能够满足大多数对象的需求。如果有某一类对象需要在共享堆上创建和共享,这种需求是比较合理的,可以在这个类的 new 和 delete 上实现共享保护。
B
进程上下文:
当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为
该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态
,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执
行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时
,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有
需要用到的资源,以便中断服务结束时能恢复被中断进程的执行。
中断上下文:
硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件
的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断
上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他
环境(主要是当前被打断执行的进程环境)。中断时,内核不代表任何进程运行,它
一般只访问系统空间,而不会访问进程空间,内核在中断上下文中执行时一般不会阻
塞。
线程上下文:
当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地
的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执
行。这种切换称为“上下文切换”(“context switch”)。CPU会在一个上下文中执
行一个线程,然后切换到另外一个上下文中执行另外一个线程
当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为
该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态
,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执
行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时
,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有
需要用到的资源,以便中断服务结束时能恢复被中断进程的执行。
中断上下文:
硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件
的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断
上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他
环境(主要是当前被打断执行的进程环境)。中断时,内核不代表任何进程运行,它
一般只访问系统空间,而不会访问进程空间,内核在中断上下文中执行时一般不会阻
塞。
线程上下文:
当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地
的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执
行。这种切换称为“上下文切换”(“context switch”)。CPU会在一个上下文中执
行一个线程,然后切换到另外一个上下文中执行另外一个线程