一个进程是某种类型的活动,它有程序、输入、输出以及状态。如果一个程序运行了两次,那算作两个进程。
进程(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中,进程和它的所有子进程以及后裔共同组成一个进程组。
在传统操作系统中,每个进程有一个地址空间和一个控制线程,不过经常也存在同一个地址空间中准并行运行多个控制线程的情形,这些线程就像分离的进程(共享地址空间除外)。
引入线程的原因
类比创建一个 Java 进程和 Java 线程的成本。
进程是资源管理的单位,进程拥有存放程序正文和数据以及其他资源的地址空间。这些资源中包括打开的文件,子进程、即将发生的定时器、信号处理程序、账号信息等。
线程是资源(cpu)调度的单位,线程概念实现的是:共享这一组资源的多个线程的执行能力,以便这些线程可以完成某一任务而共同工作。每一个线程有其自己的堆栈, 因为每个线程通常都会有不同的调用过程,从而有一个各自不同的执行历史。
进程拥有一个执行的线程,通常简称为线程,由于线程具有进程的某些特质,所有有时也称为轻量级的进程(lightwight process) 。在线程中有一个程序计数器,用来记录接着要执行那一条指令,线程拥有寄存器,用来保存线程当前的工作变量。线程还拥有一个堆栈、用来记录执行历史,其中每一帧保存了一个已调用但是还没有从中返回的过程。
尽管线程必须在进程中执行,但线程和它的进程是不同的概念,进程用于把资源集中到一起,而线程则是在 CPU 上被调度执行的实体。
实现 进程间通信(InterProcess Communication,IPC) 主要有三个问题
这三个问题中,后两个对于线程也同样适用。第一个问题(传递消息)对线程而言比较容易,因为它们共享一个地址空间(在不同地址空间需要通信的线程属于不同进程之间通信的情形)。但是另外两个问题,在线程间与进程间是相同的,并且也可通过相同的方法解决。
竞态条件(race condition) :两个或多个进程(线程)读取某些共享数据,而最后的结果取决于进程(线程)的精确时序。
凡涉及共享内存、共享文件以及共享任何资源的情况都会引发竞态条件问题
避免竞态条件的关键是互斥(mutual exclusion):一个进程在使用一个共享变量或文件时,其他进程不能做同样的操作,阻止多个进程同时读写共享的数据,
临界区(citical section) :对共享内存进行访问的程序片断。
只要保证两个进程不能同时进入临界区,就能避免竞态条件。