进程

  1. 一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。在某一瞬间,一个cpu只能运行一个进程,但在一秒钟期间,它可能运行多个进程,这样就产生并行的错觉
  2. 有4种主要事件导致进程的创建:
    (1)系统初始化
    (2)执行了正在运行的进程所调用的进程创建系统调用
    (3)用户请求创建一个新进程
    (4)一个批处理作业的初始化
  3. 在unix系统中只有一个系统调用可以用来创建新进程:fork。这个系统调用会创建一个与调用进程相同的副本,在调用fork之后父子进程拥有相同的存储映像、同样的环境字符串和同样的打开文件
  4. 在windows中,一个win32函数调用CreateProcess既处理进程的创建,也负责把正确的程序装入新的进程,除了这个函数外,win32中有大约100个其他的函数用于处理进程的管理、同步以及相关的事务
  5. 进程的终止通常由下列条件引起:
    (1)正常退出(自愿):unix:exit系统调用 windows:ExitProcess函数
    (2)出错退出(自愿):执行非法指令、引用非法内存、除数是0等原因
    (3)严重错误(非自愿)
    (4)被其他进程杀死(非自愿):unix:kill系统调用 windows:TerminateProcess函数
  6. unix中,进程和它的所有子女进程以及后裔共同组成一个进程组,整个系统中所有的进程就是以init为根的一棵树。而windows中没有进程层次的概念,所有进程的地位都是相同的,但是在创建进程的时候父进程会得到一个特别的句柄可以用来控制子进程,而父进程有权把句柄传送给某个其他进程,但是unix中就不能剥夺其子女的继承权
  7. 进程三种形态:
    (1)运行态(该时刻实际占用CPU)
    (2)就绪态(可运行,但因为其他进程正在运行而暂时停止)
    (3)阻塞态(除非某种外部事件,否则进程不能运行)
  8. 为了实现进程模型,操作系统维护着一张进程表,每个进程占用一个进程表项,也叫做进程控制块(PCB),该表项包含了进程状态的重要信息,包括程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息,以及其他由运行态切换到就绪态或阻塞态时必须保存的信息,从而保证该进程随后能再次启动

线程

  1. 多线程产生的主要原因是许多应用中同时发生着多种活动,其中某些活动随着时间的推移会被阻塞。通过将这些应用程序分解成可以准并行运行的多个顺序线程,程序模型会变得简单。并且有了多线程概念后,我们可以让并行实体(线程)共享同一个地址空间和所有可用数据的能力,而多进程则不行,因为它们具有不同的地址空间
  2. 第二个需要多线程的理由是:由于线程比进程更轻量级,因此线程比进程更容易创建也更容易撤销,第三个需要多线程理由是进程中如果有I/O密集型线程和CPU密集型线程将提升系统的性能
  3. 一个进程中的所有线程共享地址空间、同一个打开文件集、子进程、报警和相关信号等,而每个线程则享有自己的程序计数器、寄存器、堆栈和状态。
  4. 在多线程情况下,进程通常会从当前主线程开始,这个线程可以通过调用库函数thread_create创建新的线程,创建线程通常都会返回一个线程标识符,该标识符就是新线程的名字。当一个线程完成工作后,可以通过调用thread_exit退出,也可以通过调用thread_join等待另一个线程退出。
  5. 另一个常用的线程调用是thread_yield,它允许线程自动放弃CPU从而让另一线程运行。不同于进程,线程无法利用时钟中断强制线程让出CPU。
  6. pthread线程库是可移植的线程程序,大部分UNIX系统都支持该标准
  7. 有两种主要的方式实现线程包:在用户空间和在内核中。用户级线程包可以在不支持线程的操作系统上实现。在用户空间管理线程时,每个进程需要有其专用的线程表,用来跟踪该进程中的线程。用户级线程包在进行线程调度切换时由于保存该线程状态的过程和调度过程都只是本地过程,并且不需要陷阱,不需要上下文切换,不需要对内存高速缓存进行刷新,这使得线程调度非常快捷,比进程切换要快很多
  8. 用户级线程得另一个优点是允许每个进程有自己定制的调度算法
  9. 用户级线程存在的问题有:阻塞系统调用问题、页面故障问题以及线程一旦开始运行除非这个线程自动放弃CPU否则该线程中的其他线程就不能运行。
  10. 在内核中实现线程时,在内核中有记录系统中所有线程的线程表,当某个线程希望创建一个新线程或者撤销一个已有线程时,线程表将进行一个系统调用,这个系统调用通过对线程表的更新完成线程创建或撤销工作
  11. 内核级线程由于内核控制线程因此不存在阻塞系统调用、页面故障这些问题,但是由于在内核中创建和销毁线程会比用户级线程速度慢
  12. 为了使得内核级线程有更好的性能,人们提出了一种调度程序激活机制。当使用该机制时,内核给每个进程安排一定数量的虚拟处理器并且在运行时系统将线程分配到处理器上。

进程间通信(IPC)

  1. 由于进程之间会共享某些公共地址并且由于进程之间的运行次序不确定,因此进程之间会存在竞争条件
  2. 要避免竞争条件的关键是找出某种途径来阻止多个进程同时读写共享的数据,因此我们需要的是互斥,即以某种手段确保当一个进程在使用一个共享变量或文件时,其他进程不能做同样的操作
  3. 一个好的解决方案,需要满足以下4个条件:
    (1)任何两个进程不能同时处于临界区
    (2)不应对CPU的速度和数量做任何假设
    (3)临界区外运行的进程不得阻塞其他进程
    (4)不得使进程无限期等待进入临界区
  4. 忙等待的互斥:
    (1)屏蔽中断:每个进程进入临界区之后屏蔽中断,屏蔽中断之后CPU将不会被切换到其他进程,但是如果是多处理器系统仅仅对某个CPU有效,其他CPU仍在运行
    (2)锁变量:锁变量依然会导致竞争条件
    (3)严格轮换法:临界区外的进程会阻塞其他进程
    (4)Peterson解法:将锁变量与警告变量的思想相结合
    (5)TSL指令:需要硬件支持
  5. 信号量semaphore,针对n种资源需要n种信号量,信号量只有两种操作P(down)、V(up),使用信号量时一定要注意避免死锁
  6. 互斥量mutex,互斥量是信号量的简化版本,在实现时既容易又有效,使得互斥量在实现用户空间线程包时十分有用
  7. 为了更易于编写正确的程序提出了一种高级的原语管程(monitor)。进程可在任何需要的时候调用管程中的过程,但它们不能在管程之外声明的过程中直接访问管程内的数据结构
  8. 管程有一个很重要的特性,即任一时刻管程中只能有一个活跃的进程,这一特性使得管程能够有效地完成互斥
  9. 消息传递,这种进程间通信使用两条原语sendreceive,是系统调用而不是语言成分,通常在并行程序设计系统中使用消息传递
  10. 最后一个同步机制屏障,主要准备用于进程组而不是用于双进程,可以通过在每个阶段的结尾设置屏障来实现所有进程都准备进入下一阶段时才能允许进程进入下一阶段