线程理解

 线程的产生
  在线程概念出现之前,进程是系统进行资源分配的基本单位,按进程为单位分配资源。同时,进程也是处理器调度的基本单位,进程在任一时刻只有一个执行控制流,通常将这种结构的进程称单线程(结构)进程(single threaded process)。这个时候进程和线程概念可以不加区别。
  但进程存在一些问题:
●进程时空的开销大,频繁的进程调度将耗费大量处理器时间,要为每个进程分配存储空间限制了操作系统中进程的总数。
●进程通信的代价大,每次通信均要涉及通信进程之间或通信进程与操作系统之间的信息传递。
●进程之间的并发性粒度较粗,并发度不高,过多的进程切换和通信延迟使得细粒度的并发得不偿失。
●不适合并行计算和分布并行计算的要求,对于多处理器和分布式的计算环境来说,进程之间大量频繁的通信和切换,会大大降低并行度。
●不适合客户/服务器计算的要求。对于C/S 结构来说,那些需要频繁输入输出并同时大量计算的服务器进程(如数据库服务器、事务监督程序)很难体现效率。
  于是线程的概念开始浮出水面,如果说操作系统中引入进程的目的是为了使多个程序能并发执行,以改善资源使用率和提高系统效率,那么,在操作系统中再引入线程,则是为了减少程序并发执行时所付出的时空开销,使得并发粒度更细、并发性更好。
  这里解决问题的基本思路是:把原先进程的两项功能--“独立分配资源”与“被调度分执行”分离开来,前一项任务仍由进程完成,它作为系统资源分配和保护的独立单位,不需要频繁地切换;后一项任务交给称作线程的实体来完成,它作为系统调度和分派的基本单位,会被频繁地调度和切换,在这种指导思想下,产生了线程的概念。
 
线程的设计
  线程出现之前的进程拥有进程和线程的双重职责,分别是对资源的管理和实际的指令执行序列,如下图:
  
                          单线程进程的内存布局
 
  设想如果把进程的管理和执行任务相分离,让进程是操作系统中进行保护和资源分配的单位,允许一个进程中包含多个可并发执行的控制流,这些控制流切换时不必通过进程调度,通信时可以直接借助于共享内存区,每个控制流称为一个线程,如下图:
      
                  管理和执行相分离的进程,将执行序列作为线程
 
多线程进程
  在多线程环境中,仍然有与进程相关的内容是PCB 和用户地址空间,而每个线程除了有独立堆栈,以及包含现场信息和其他状态信息外,也要设置线程控制块TCB(Thread Control Block)。线程间的关系较为密切,一个进程中的所有线程共享其所属进程拥有的资源,它们驻留在相同的地址空间,可以存取相同的数据。例如,当一个线程改变了主存中一个数据项时,如果这时其他线程也存取这个数据项,它便能看到相同的结果。
 
  最后,给出多线程环境中进程的定义:进程是操作系统中进行保护和资源分配的基本单位。它具有:
●一个虚拟地址空间,用来容纳进程的映像;
●对处理器、其他(通信的)进程、文件和 I/O 资源等的有控制有保护的访问。
●而传统进程原先所承担的控制流执行任务交给称作线程的部分完成。
 
  多线程环境中线程具有:
● 当线程不运行时,有一个受保护的线程上下文,用于存储现场信息。所以,观察线程的一种方式是运行在进程内一个独立的程序计数器。
●一个执行堆栈。
●一个容纳局部变量的主存存储区。
●并发性,共享性。
 

 

ps.线程上下文切换:

在高性能编程时,经常接触到多线程. 起初我们的理解是, 多个线程并行地执行总比单个线程要快, 就像多个人一起干活总比一个人干要快. 然而实际情况是, 多线程之间需要竞争IO设备, 或者竞争锁资源,导致往往执行速度还不如单个线程. 在这里有一个经常提及的概念就是: 上下文切换(Context Switch). 

上下文切换的精确定义可以参考: http://www.linfo.org/context_switch.html. 下面做个简单的介绍. 多任务系统往往需要同时执行多道作业.作业数往往大于机器的CPU数, 然而一颗CPU同时只能执行一项任务, 如何让用户感觉这些任务正在同时进行呢? 操作系统的设计者巧妙地利用了时间片轮转的方式, CPU给每个任务都服务一定的时间, 然后把当前任务的状态保存下来, 在加载下一任务的状态后, 继续服务下一任务. 任务的状态保存及再加载, 这段过程就叫做上下文切换. 时间片轮转的方式使多个任务在同一颗CPU上执行变成了可能, 但同时也带来了保存现场和加载现场的直接消耗. 
(Note. 更精确地说, 上下文切换会带来直接和间接两种因素影响程序性能的消耗. 直接消耗包括: CPU寄存器需要保存和加载, 系统调度器的代码需要执行, TLB实例需要重新加载, CPU 的pipeline需要刷掉; 间接消耗指的是多核的cache之间得共享数据, 间接消耗对于程序的影响要看线程工作区操作数据的大小). 

posted @ 2014-01-23 21:45  寂静沙滩  阅读(506)  评论(0编辑  收藏  举报