经典线程模型

线程模型

线程模型

进程模型基于两种独立的概念:资源分组处理与执行。有时,将这两种概念分开会更有益,这也引入了“线程”这一概念。我们将先来看经典的线程模型:

理解进程的一个角度是,用某种方法把相关的资源集中在一起。进程有存放程序正文和数据以及其他资 源的地址空间。这些资源中包括打开的文件、子进程、即将发生的报警、信号处理程序、账号信息等。把它 们都放到进程中可以更容易管理

另一个概念是,进程拥有一个执行的线程,通常简写为线程(thread)。在线程中有一个程序计数器, 用来记录接着要执行哪一条指令。线程拥有寄存器,用来保存线程当前的工作变量。线程还拥有一个堆栈, 用来记录执行历史,其中每一帧保存了一个已调用的但是还没有从中返回的过程。尽管线程必须在某个进程 中执行,但是线程和它的进程是不同的概念,并且可以分别处理。进程用于把资源集中到一起,而线程则是 在CPU上被调度执行的实体

线程给进程模型增加了一项内容,即在同一个进程环境中,允许彼此之间有较大独立性的多个线程执 行。在同一个进程中并行运行多个线程,是对在同一台计算机上并行运行多个进程的模拟。在前一种情形 下,多个线程共享同一个地址空间和其他资源。而在后一种情形中,多个进程共享物理内存、磁盘、打印机 和其他资源。由于线程具有进程的某些性质,所以有时被称为轻量级进程(lightweight process)。多线程这 个术语,也用来描述在同一个进程中允许多个线程的情形

在图a中,可以看到三个传统的进程。每个进程有自己的地址空间和单个控制线程。相反,在图b中,可以看到一个进程带有三个控制线程。尽管在两种情形中都有三个线程,但是在图a中,每一个线程都在不同的地址空间中运行,而在图b中,这三个线程全部在相同的地址空间中运行

在这里插入图片描述
当多线程进程在单CPU系统中运行时,线程轮流运行,通过在多个进程之间来回切换,系统制造了不同的顺序进程并行运行的假象。多线程的工 作方式也是类似的。CPU在线程之间的快速切换,制造了线程并行运行的假象,好似它们在一个比实际CPU 慢一些的CPU上同时运行。在一个有三个计算密集型线程的进程中,线程以并行方式运行,每个线程在一个 CPU上得到了真实CPU速度的三分之一,进程中的不同线程不像不同进程之间那样存在很大的独立性。所有的线程都有完全一样的地址空间,这 意味着它们也共享同样的全局变量。由于各个线程都可以访问进程地址空间中的每一个内存地址,所以一个 线程可以读、写或甚至清除另一个线程的堆栈,不同的进程会来自不同的用户,它们彼此之间可能有敌意,一个进程总是由 某个用户所拥有,该用户创建多个线程应该是为了它们之间的合作而不是彼此间争斗。除了共享地址空间之 外,所有线程还共享同一个打开文件集、子进程、报警以及相关信号等,如图所示。这样,对于三个没有关系的线程而言,应该使用图a的结构,而在三个线程实际完成同一个作业,并彼此积极密切合作的情形中,图b则比较合适

在这里插入图片描述
图中,第一列表项是进程的属性,而不是线程的属性。例如,如果一个线程打开了一个文件,该文 件对该进程中的其他线程都可见,这些线程可以对该文件进行读写。由于资源管理的单位是进程而非线程, 所以这种情形是合理的。如果每个线程有其自己的地址空间、打开文件,即将发生的报警等,那么它们就应 该是不同的进程了。线程概念试图实现的是,共享一组资源的多个线程的执行能力,以便这些线程可以为完 成某一任务而共同工作

和传统进程一样(即只有一个线程的进程),线程可以处于若干种状态的任何一个:运行、阻塞、就绪 或终止。正在运行的线程拥有CPU并且是活跃的。被阻塞的线程正在等待某个释放它的事件。例如,当一个 线程执行从键盘读入数据的系统调用时,该线程就被阻塞直到键入了输入为止。线程可以被阻塞,以便等待 某个外部事件的发生或者等待其他线程来释放它。就绪线程可被调度运行,并且只要轮到它就很快可以运 行。线程状态之间的转换和进程状态之间的转换是一样的

在这里插入图片描述

认识到每个线程有其自己的堆栈很重要,如图所示。每个线程的堆栈有一帧,供各个被调用但是还 没有从中返回的过程使用。在该帧中存放了相应过程的局部变量以及过程调用完成之后使用的返回地址,例如,如果过程X调用过程Y,而Y又调用Z,那么当Z执行时,供X、Y和Z使用的帧会全部存在堆栈中。通常 每个线程会调用不同的过程,从而有一个各自不同的执行历史。这就是为什么每个线程需要有自己的堆栈的原因

在多线程的情况下,进程通常会从当前的单个线程开始。这个线程有能力通过调用一个库函数(如 thread_create)创建新的线程。thread_create的参数专门指定了新线程要运行的过程名。这里,没有必要对新 线程的地址空间加以规定,因为新线程会自动在创建线程的地址空间中运行。有时,线程是有层次的,它们 具有一种父子关系,但是,通常不存在这样一种关系,所有的线程都是平等的。不论有无层次关系,创建线 程通常都返回一个线程标识符,该标识符就是新线程的名字

当一个线程完成工作后,可以通过调用一个库过程(如thread_exit)退出。该线程接着消失,不再可调 度。在某些线程系统中,通过调用一个过程,例如thread_join,一个线程可以等待一个(特定)线程退出。 这个过程阻塞调用线程直到那个(特定)线程退出。在这种情况下,线程的创建和终止非常类似于进程的创 建和终止,并且也有着同样的选项

另一个常见的线程调用是thread_yield,它允许线程自动放弃CPU从而让另一个线程运行。这样一个调用 是很重要的,因为不同于进程,(线程库)无法利用时钟中断强制线程让出CPU。所以设法使线程行为“高 尚”起来,并且随着时间的推移自动交出CPU,以便让其他线程有机会运行,就变得非常重要。有的调用允 许某个线程等待另一个线程完成某些任务,或等待一个线程宣称它已经完成了有关的工作等

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值