《现代操作系统》进程与线程

进程与线程

《现代操作系统》进程与线程 笔记

进程

一个进程是某种类型的活动,它有程序、输入、输出以及状态。如果一个程序运行了两次,那算作两个进程。

进程(process):在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干顺序进程(sequential process),一个进程就是一个正在执行程序的实例,包括程序计数器和变量的当前值。

从概念上说每个进程都拥有它自己的虚拟CPU(实际上真正的CPU在个进程之间来回切换)

进程管理 相关的系统调用

调用说明
pid = fork()创建于父进程相同的子进程
pid = waitpid(pid,&statloc,options)等待一个子进程终止
s = execve(name,argv,environp)替换一个进程的核心映像
exit(status)终止一个进程并返回状态

进程的创建

在UNIX系统中,只要一个系统调用可以创建进程:fork,这个系统调用会创建一个与调用进程相同的副本。在调用了fork后,这两个进程(父进程和子进程)拥有相同的内存映像、同样的环境字符串和同样的打开文件。通常子进程接着执行 execve 或者一个类似的系统调用,以修改其内存映像并运行一个新的程序。

写时复制(copy-on-write):在UNIX中,子进程初始地址空间是父进程的一个副本,但只这里涉及两个不同的地址空间,不可写的内存区是共享的,可写的内存是不可以共享的。某些UNIX的实现使程序正文在两者间共享,因为不可写内存不能修改,因此二者可以共享。但对于可以内存,内存通过 写时复制(copy-on-write) 共享,一旦两者之一想要修改部分内存,则这块内存首先被明确的复制,以确保修改发生在私有内存区域。

进程的终止

进程退出的几种情况

  • 正常退出(自愿的)
  • 出错退出(自愿的):参数等导致的错误
  • 严重错误(非自愿):程序中的错误
  • 被其他进程杀死(非自愿)

进程退出的系统调用:

  • UNIX:exit
  • windows:ExitProcess

进程的层次结构

在UNIX中,进程和它的所有子进程以及后裔共同组成一个进程组。

进程的状态

线程

在传统操作系统中,每个进程有一个地址空间和一个控制线程,不过经常也存在同一个地址空间中准并行运行多个控制线程的情形,这些线程就像分离的进程(共享地址空间除外)。

引入线程的原因

  • 第一个原因:线程的加入,使得并行实体拥有共享一个地址空间和所有可用数据的能力。对于某些应用而言,这种能力是必须的,二者正式多进程模型(它们具有不同的地址空间)所无法表达的。
  • 第二个原因:由于线程比进程更轻量级,所以它比进程更容易(即更快)创建,也更容撤销。在许多系统中,创建一个线程要比创建一个进程快10~100倍。
  • 第三个原因:涉及性能,对于 CPU 密集型的应用,多线程并不能获得性能上的增强,但如果存在大量的 I/O 处理,拥有多个线程允许这些活动彼此重叠,从而加快应用程序的执行速度。
  • 第四个原因:在多 CPU 系统中,多线程是有益的,可以真正的实现并行。

类比创建一个 Java 进程和 Java 线程的成本。

进程是资源管理的单位,进程拥有存放程序正文和数据以及其他资源的地址空间。这些资源中包括打开的文件,子进程、即将发生的定时器、信号处理程序、账号信息等。

线程是资源(cpu)调度的单位,线程概念实现的是:共享这一组资源的多个线程的执行能力,以便这些线程可以完成某一任务而共同工作。每一个线程有其自己的堆栈, 因为每个线程通常都会有不同的调用过程,从而有一个各自不同的执行历史。

进程拥有一个执行的线程,通常简称为线程,由于线程具有进程的某些特质,所有有时也称为轻量级的进程(lightwight process) 。在线程中有一个程序计数器,用来记录接着要执行那一条指令,线程拥有寄存器,用来保存线程当前的工作变量。线程还拥有一个堆栈、用来记录执行历史,其中每一帧保存了一个已调用但是还没有从中返回的过程。

尽管线程必须在进程中执行,但线程和它的进程是不同的概念,进程用于把资源集中到一起,而线程则是在 CPU 上被调度执行的实体。

进程间通信

实现 进程间通信(InterProcess Communication,IPC) 主要有三个问题

  1. 一个进程如何把消息传递给另一个
  2. 确保两个活多个进程在关键活动中不会出现交叉
  3. 正确的顺序

这三个问题中,后两个对于线程也同样适用。第一个问题(传递消息)对线程而言比较容易,因为它们共享一个地址空间(在不同地址空间需要通信的线程属于不同进程之间通信的情形)。但是另外两个问题,在线程间与进程间是相同的,并且也可通过相同的方法解决。

竞态条件(race condition) :两个或多个进程(线程)读取某些共享数据,而最后的结果取决于进程(线程)的精确时序。

凡涉及共享内存、共享文件以及共享任何资源的情况都会引发竞态条件问题

避免竞态条件的关键是互斥(mutual exclusion):一个进程在使用一个共享变量或文件时,其他进程不能做同样的操作,阻止多个进程同时读写共享的数据,

临界区(citical section) :对共享内存进行访问的程序片断。

只要保证两个进程不能同时进入临界区,就能避免竞态条件。

信号量(semaphore) :使用一个整数变量来累计唤醒次数。一个信号量的取值可为0(表示没有保存下来的唤醒操作)或者为正(表示一个或多个唤醒操作)。
信号量一般有两种操作 down 和 up;对一个信号量执行down操作,则是检查其值是否大于0;若大于0,则将其值减一(即用掉一个保存的信号量)并继续;若该值为0,则将继续睡眠,而且此时down操作并未结束。up 操作对信号量值增1,如果一个或多个进程在该信号量上睡眠,无法完成一个先前的down操作,则由系统选择其中一个(如随机挑选)并允许该进程完成down操作。于是,对一个进程在骑上睡眠的信号量执行一次 up 操作之后,该信号量的值任为0,但在其上睡眠的进程却少了一个。信号量的增1和唤醒一个进程同样是不可分割的。

检查数值、修改变量值以及可能发生的睡眠操作均作为一个单一的、不可分割的原子操作完成。保证一旦一个信号量操作开始,则在该操作完成或阻塞之前,其他进程均不允许访问该信号量。

原子操作:是指一组相关联的操作要么不间断的执行,要么都不执行。

如果不需要信号量的计数能力,有时可以使用信号量的简化版本互斥量(mutex)

管程(monitor) :一个管程是一个由过程、变量及数据结构等组成的一个特殊的模块。管城有一个重要的特性:任一时刻管程中只能有一个活跃的进程,这一特性使得管程能有效的完成互斥。

管程典型的处理方法是,当一个进程调用管程过程时,该过程中的前几条指令将检查在管程中是否有其他的活跃进程。如果有调用进程将被挂起,直到另一个进程离开管程将其唤醒。如果没有活跃进程使用管程,则该调用进程可以进入。

管程是一个编程语言概念,编译器必须要识别管程并用某种方式对其互斥做出安排。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值