进程与线程

进程

在任何多道程序涉及系统中,CPU由一个进程快速切换至另一个进程,使每个进程各运行几十或几百秒。严格的来说,在某一瞬间,CPU只能运行一个进程,但在1秒钟内,它可能运行多个进程,这样产生了一种并行的错觉。 进程 ,由一组执行的指令一个当前的状态一组相关的系统资源表征的活动单元。

也可以把进程视为一组元素组成的实体,进程的两个基本元素是程序代码和与代码相关的数据集。进程被创建时,系统会创建和管理与之相应的进程控制块(Process Control Block,PCB),这种数据结构包括标识符、状态、优先级、程序计数器、内存指针、上下文数据、I/O 状态信息和记账信息。

在迄今为止的讨论中,进程具有如下两个特点:

  • 资源所有权 进程包括存放在进程映像的虚拟地址空间,进程映像是包括程序、数据、栈和进程控制块中定义的属性集。进程总具有对资源的控制权和有所有权,这些资源包括内存、I/O通道、I/O设备和文件。操作系统提供预防进程间发生不必要的资源冲突的保护功能
  • 调度/执行 进程执行时采用一个或多程序的执行路径,不同进程的执行过程会交替进行。因此,进程具有执行态和分配给其的优先级,是可被操作系统调度和分派的实体。

因此,进程可以是说是由程序代码与相关数据及进程控制块组成。

进程创建的步骤

  1. 为新进程分配一个唯一的进程标识符
  2. 为进程分配空间
  3. 初始化进程控制块
  4. 设置正确的链接:例如,若操作系统将每一个调度队列都维护为一个链表,则新进程必须放在就绪或者就绪/挂起链表中。
  5. 创建或扩充其他数据结构。为每一个进程创建一个记账文件

进程切换的步骤

  1. 保存处理器的上下文,包括程序计数器和其它寄存器
  2. 更新当前处于运行态的进程的进程控制块,包括把进程的状态改变为另一状态。
  3. 把改进程的程序控制块移到相应的队列
  4. 选择另一个进程执行
  5. 更新所选进程的程序控制块,包括把进程的状态改为运行态
  6. 更新内存管理数据结构
  7. 载入程序计数器和其它寄存器的值,将处理器的上下文恢复为所选进程上次退出时保存的运行上下文

UNIX创建新进程的步骤

UNIX创建新进程由内核系统调用函数fork()实现。一个进程发出一个fork请求时:

  1. 在进程表中为新进程分配一项
  2. 为子进程分配唯一一个进程标识符
  3. 复制父进程的进程映像,但共享内存除外(Linux对此有优化)
  4. 增加父进程所拥有文件的计数器,反映了另一个进程也拥有这些文件的事实
  5. 将子进程设置为就绪态
  6. 将子进程的ID号返回给父进程,将0值返回给子进程。

线程

多线程是指操作系统在单个进程内支持多个并发执行路径的能力。每个进程中仅执行单个线程的传统方法称为单线程方法。

为啥要用线程?

相比进程,线程具有的优点:

  1. 在已有进程中创建一个新线程的时间,远少于创建一个全新进程的时间
  2. 终止一个线程的时间比终止进程所花的时间少
  3. 同一进程内线程切换的时间要少于进程之间的切换时间
  4. 线程提高了不同程序之间通信的效率。在多数操作系统中,独立进程间的通信需要内核的介入,以提供保护和通信所需的机制。由于同一进程中的多个线程共享内存和文件,因此它们无需调用内核就可以互相通信。

Linux线程

Linux提供一种不区分进程和线程的解决方案。通过复制当前进程的属性可创建一个新的进程。新进程创建后,可以共享资源,比如文件、信号处理程序和虚存。两个进程有共享的相同的虚存时,可将它们视为一个进程中的线程。==然而,Linux没有专门为线程单独定义数据结构,因此Linux中的进程和线程没有区别。==Linux用clone()命令代替通常的fork()命令来创建进程(传统的fork()使用clone()系统调用实现的)。

Linux命名空间

Linux中和每个进程相关联的是一组命名空间。命名空间可以使一个进程(或共享同一命名空间下的多个进程)拥有与其它命令空间的其他进程不同的系统视图。当前Linux下有6种命名空间,即mnt、pid、net、ipc、uts和user。

进程与线程的一个简单解释

[source: http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html]

进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握。

  1. 计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。

  2. 假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。

  3. 进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

  4. 一个车间里,可以有很多工人。他们协同完成一个任务。

  5. 线程就好比车间里的工人。一个进程可以包括多个线程。

  6. 车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存

  7. 可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。

  8. 一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。

  9. 还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。

  10. 这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。

    不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

  11. 操作系统的设计,因此可以归结为三点:

    1. 以多进程形式,允许多个任务同时运行;
    2. 以多线程形式,允许单个任务分成不同的部分运行;
    3. 提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源
最近更新: 1/26/2019, 9:26:10 PM