操作系统概念 进程概述

进程

进程概念

进程

进程是执行中的程序,这只是非正式的说法。进程不只是程序代码,程序代码称为文本段(代码段),还包括当前活动,通过程序计数器(PC)的值和处理器寄存器的内容来表示。此外,进程还包括进程堆栈段(临时数据、函数参数、局部变量、地址)和数据段(包括全全局变量。还可能包括堆(leap),是在进程运行期间动态分配内存。

程序是被动实体,如存储在磁盘上包含一系列指令的文件内容(可执行文件),而进程是一个活动实体,他有一个程序计数器来表示下一个要执行的命令和相关资源集合。

虽然两个进程可以与同一程序相关,如同一用户调用的不同web浏览器副本,但他们是独立的进程。尽管代码段相同的,但数据段、堆栈等却不同。

进程状态

进程状态:

  • 新的(NEW):进程正在被创建
  • 运行(RUNNING):指令正在被执行
  • 等待(WAIT):进程等待某个事件的发生(如I/O完成或受到信号)
  • 就绪 (READY):进程等待分配处理器
  • 终止(TERMINAL):进程完成执行

一次只有一个进程可以在一个处理器上运行,但多个进程可以处于就绪或等待状态。

进程控制块(PCB)

进程在操作系统内用进程控制块(process control block,PCB)来表示,PCB包含了进程状态、程序计数器、cpu寄存器、cpu调度信息、内存管理信息、记账信息、I/O状态信息等信息。

  • 进程状态(Process state): 状态可包括新的,就绪,运行,等待,终止等。
  • 程序计数器(Program counter) : 计数器表示进程要执行的下个指令的地址。
  • CPU寄存器(CPU registers):与程序计数器一起,这些寄存器的状态信息在出现中断时也需要保存,以便进程以后能正确的执行。
  • CPU调度信息(CPU scheduling information):这类信息包括进程优先级、调度队列指针和其他调度参数。
  • 内存管理信息(Memory-management information):根据内存系统,这类信息包括基址和界限寄存器的值,页表或段表。
  • 记账信息(Accounting information):这类信息包括CPU时间、实际使用时间、时间界限、记账数据、作业或进程数量等。
  • I/O状态信息(I/O status information):这类信息包含分配给进程的I/O设备列表、打开的文件列表等。 

进程调度

多道程序设计的目的是无论何时都有进程执行,从而使CPU利用率达到最大。分时系统的目的是在进程之间快速切换CPU以便用户在程序运行时能与其进行交互。为达到这一目的,进程调度选择一个可用的进程到CPU上执行。单处理器系统从不会有超过一个进程在执行。如果有多个进程,那么余下的则需要等待CPU空闲并且重新调度。

调度队列

进程进入系统时,会被加入到作业队列中,该队列包含系统中所有进程。驻留在内存中就绪的、等待运行的程序保存在就绪队列中。该队列常用链表来实现,其头节点指向链表的第一个和最后一个PCB块的指针。每个PCB包括一个指向就绪队列的下一个PCB的指针域。

Linux 中每一个进程都由task_struct 数据结构来定义. task_struct就是我们通常所说的PCB,还包含有指向父进程和子进程的指针。例如,进程的状态就是通过这个结构中的long state字段来表示的。

linux内核里,所有活动的进程是通过一个名为task_struct的双向链表来表示的,内核为当前正在运行的进程保存了一个指针。

如内核想把当前运行的进程状态值修改成 new_state。如果current是指向当前进程的指针,则:

current -> state = new_state;

新进程开始处于就绪队列,它就在就绪队列中等待直到被选中执行或被派遣。当进程分配到CPU执行时,可能发生:

  1. 进程发出一个IO请求,并放到IO队列中。
  2. 进程创建新的子进程,并等待其结束
  3. 进程由于中断而强制释放cpu,并被放回到就绪队列中

对于前两种情况,进程最终从等待状态切换到就绪状态,并放回到就绪队列中。进程继续这一循环直到终止,到那时它将从所有队列中删除,其PCB和资源将得以释放。

调度程序

进程会在各种调度队列之间迁移,为了调度,操作系统必须按某种方式从这些队列中选择进程。进程的选择是由相应的调度程序(scheduler)来执行的。

通常批处理系统中,进程更多的是被提交,而不是马上执行。这些进程通常放到磁盘的缓冲池里,以便以后执行。长期调度程序或作业调度程序从该池中选择进程,并装入内存以准备执行。短期调度程序或cpu调度程序从准备执行的进程中选择进程,并为之分配cpu。

这两个调度程序的主要差别是调度的频率。

短期调度程序通常100ms至少执行一次,由于每次执行之间的时间较短,短期调度程序必须要快。 
Short-term scheduler is invoked very frequently (milliseconds) ? (must be fast).

长期调度程序执行的并不频繁,所以长期调度程序能使用更多的时间来选择执行进程。 
Long-term scheduler is invoked very infrequently (seconds, minutes) ? (may be slow).

长期调度程序控制多道程序设计的程度(内存中进程的数量degree of multiprogramming)。长期调度程序必须仔细选择执行进程。通常,绝大多数进程可分为:

I/O-bound process – spends more time doing I/O than computations, many short CPU bursts. 
CPU-bound process – spends more time doing computations; few very long CPU bursts.

I/O为主的进程通常执行I/O方面比执行计算花费更多时间,另一方面,CPU为主的进程很少产生I/O请求。为使系统达到平衡和更好的性能,长期调度程序应当选择一个合理的包含IO为主的和CPU为主的组合进程以充分使用设备和短期调度程序。

对于Linux和Windows系统通常没有长期调度程序,这些系统的稳定性依赖于物理限制,如果系统性能下降很多,会有用户的退出。

有的系统如分时系统,可能引入中期调度程序,其核心思想是能够将进程从内存中移出,从而降低多道程序设计的程度,之后进程可以被换入。

上下文切换

中断使CPU从当前任务改变为运行内核子程序(这句话说的其实不全面,运行内核子程序则是系统调用,系统调用是软中断的一种)。当发生一个中断时,系统需要保存当前运行在CPU中进程的上下文,从而能在其处理完后恢复上下文。进程的上下文用PCB来表示。通常通过执行一个状态保存(state save)来保存CPU当前状态,之后执行一个状态恢复(state restore)重新开始运行。

将CPU切换到另一进程需要保存当前状态并恢复另一进程状态,这叫做上下文切换(context switch)。当发生上下文切换时,内核会将旧进程的状态保存在PCB中,然后装入经调度要执行的并已保存的新进程的上下文。

上下文切换时间是额外开销,因为切换时系统并不能做什么有用的工作。其切换时间与硬件支持密切相关。

进程操作

进程创建

进程在执行时,能通过创建进程系统调用创建多个新进程。创建进程为父进程,而新进程叫做子进程。新进程都可再创建其他进程,从而形成了进程树。

大多数操作系统根据一个唯一的进程标识符(process indentifier,pid)来识别进程,pid通常是一个整数值。

在UNIX中,使用ps命令可以得到一个进程列表。

通常进程需要一定的资源(如CPU时间,内存,文件,I/O设备)来完成其任务。子进程被创建时,子进程可能直接从操作系统,也可能只从父进程那里获取资源。父进程可能必须在其子进程之间分配资源或共享资源(如内存或文件),限制子进程只能使用父进程的资源能防止创建过多的进程带来的系统超载。

在进程创建时,除了得到各种物理和逻辑资源外,初始化数据(或输入)由父进程传给子进程。

当进程创建新进程被创建时,有两种执行可能:

  • 父进程与子进程并发执行
  • 父进程等待,直到某个或全部子进程执行完

新进程的地址空间也有两种可能:

  • 子进程是父进程的复制品(具有与父进程相同的程序和数据)。
  • 子进程装入另外一个新程序

UNIX操作系统中,每个进程用唯一整数标识符来标识,通过fork()系统调用,可创建新进程,新进程通过复制原来进程的地址空间而成。这种机制允许父子进程之间方便的通信。

两个进程都继续执行位于系统调用fork()之后的指令,但是对于子进程,系统调用fork的返回值为0:而对于父进程,返回值为子进程的进程标识符(非零)。

通常系统调用fork后,一个进程会使用系统调用exec(),以用新程序来取代进程的内存空间。系统调用exec()将二进制文件装入内存(消除了原来包含系统调用exec()的程序内存映射),并开始执行。采用这种方式,两个进程都能相互通信,并按各自的方式执行。

父进程能创建更多的子进程,或者如果在子进程运行时没有什么可做,那么它采用系统调用wait()把自己移出就绪队列来等待子进程的终止。

#include <cstdio>
#include <unistd.h>
#include <syspes.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <iostream>
#define debug(a) cout << #a" = " << (a) << endl;
using namespace std;

int main(int argc, char* argv[])
{
    pid_t pid;
    int f0 = 0, f1 = 1, tmp;
    pid = fork();
    if (pid < 0)
    {
        printf("Fork failed!\n");
        return -1;
    }
    else if (pid == 0)
    {
        printf("I am the son process\n");
        debug(atoi(argv[1]));
        int num = atoi(argv[1]);
        if (num < 1)
        {
            printf("Requst ilegal!\n");
            return -1;
        }
        switch(num)
        {
            case 1: printf("0\n");break;
            case 2: printf("0 1\n");break;
            default:
            {
                printf("0 1");
                for (int i = 3; i <= num; i++)
                {
                    tmp = f1;
                    f1 = f0 + f1;
                    f0 = tmp;
                    printf(" %d", f1);
                }
                printf("\n");
            }
        }
    }
    else
    {
        printf("I am the parent process\n");
        wait(NULL);
        printf("I am the parent process\n");
        printf("Parent process exit!\n");
    }
    return 0;
}

网络上找到的其他的代码,有详细解释。

当子进程完成时通过调用exit(),父进程会从wait()调用处开始继续,并调用exit()以表示结束。

进程终止

进程执行完最后的语句并使用系统调用exit()请求系统删除自身时,进程终止。此时,进程可以返回状态值(通常为整数)到父进程(通过系统调用wait())。所有进程资源(物理和虚拟内存、打开文件和I/O缓冲)会被操作系统释放。

在其他情况下也会出现终止。

进程通过适当的系统调用能终止另外一个进程。通常,只有被终止进程的父进程才能执行这一系统调用。否则,用户可以任意的终止彼此的作业。

父进程终止其子进程的原因有很多,如:

  • 子进程使用了超过它所分配的一些资源。(为判定是否发生这种情况,要求父进程有一个检查其子进程状态的机制)
  • 分配给子进程的任务已经不需要
  • 父进程退出,如果父进程终止,那么操作系统不允许子进程继续(有些操作系统,对于这类操作系统这种现象称为级联终止)。

UNIX:可以通过系统调用exit()来终止进程,父进程可以通过系统调用wait()以等待子进程的终止。系统调用wait()返回了中止子进程的进程标识符,以使父进程能够知道哪个子进程终止了。如果父进程终止,那么其所有子进程会以init进程作为父进程,因此,子进程仍然有一个父进程来收集状态和执行统计。

进程间通信

按进程是否与其他进程共享数据,可分为独立的和协作的,即独立进程或协作进程。 
可能需要提供环境以允许进程协作,理由如下:

  1. 信息共享 
    可能多个用户对同样的信息感兴趣
  2. 提高运算速度: 
    如果希望一个特定任务快速运行,那么必须将它分为子任务,每个子任务可以与其他子任务并行执行。如果要实现这样的加速,需要计算机有多个处理单元(例如CPU和I/O通道)
  3. 模块化: 
    可能需要按模块化方式构造系统
  4. 方便: 
    单个用户也可能同时执行多任务。

协作进程需要一种进程间通信机制(IPC)来允许进程相互交换数据与信息。进程间通信有两种基本模式模式:

  • 共享内存:通过建立一块供协作进程共享的内存区域并在此区域读写数据来交换信息。
  • 消息传递:通过在协作进程之间交换消息来实现通信。

对于以上两种模式,消息传递对于交换较少数据很有用,并且更易于实现,但需要更多内核介入的时间。 
共享内存比消息传递快,允许以最快速度进行方便的通信。

进程共享内存

共享内存系统需要建立共享内存区域。通常一块共享内存区域驻留在生成共享内存段进程的地址空间。其他希望使用这个共享内存段进行通信的进程必须将此放到它们自己的地址空间上。数据的形式或位置取决于这些进程而不是操作系统,进程还负责保证他们不向同一区域同时写数据。

生产者—消费者问题是协作进程的通用范例。生产者进程产生信息以供消费者进程消费。例如,编译器产生的汇编代码供汇编程序使用,而汇编程序反过来产生目标代码供连接和装入程序使用。

采用共享内存是解决生产值——消费者问题方法之一。为允许生产者进程和消费者进程能并发执行,必须有一个缓冲来被生产者填充并被消费者所使用。此缓冲驻留在共享内存区域,消费者使用一项时,生产者能产生另一项。生产者和消费者必须同步,以免消费者消费一个没有生产出的项。

可以使用两种缓冲:

无限缓冲对缓冲大小没有限制。消费者可能不得不等待新的项,但生产者总可以产生新的项。

有限缓冲假设缓存大小固定。对于这种情况,如果缓冲为空,那么消费者必须等待,如果缓冲为满,那么生产者必须等待。

# define BUFFER-SIZE 10

typedef struct     {

...

}  item;

item buffer[BUFFER-SIZE];

int  in=0;

int out=0;

共享缓存通过循环数组和两个逻辑指针in和out来实现,in指向缓冲中下一个空位;out指向缓冲中第一个满位。当in = = out时,缓冲为空;当(in+1)%BUFFER-SIZE = = out时,缓冲为满。

生产者和消费者代码如下:生产者进程有一个局部变量nextProduced以储存所产生的新项。消费者有一个局部变量nextConsumed以存储要使用的新项。

生产者进程:

while (true) {   /* Produce an item */
while (((in = (in + 1) % BUFFER SIZE count)  = = out); /*do nothing */
buffer[in] = item;
in = (in + 1) % BUFFER SIZE;
}

消费者进程:

while (true) {
while (in == out); // do nothing -- nothing to consume
// remove an item from the buffer
item = buffer[out];
out = (out + 1) % BUFFER SIZE;
return item;
}

这种方法允许缓存的最大项数是BUFFER—SIZE-

消息传递系统

消息传递提供一种机制以允许进程不必通过共享地址空间来实现通信和同步,这在分布式系统中很有用。例如用于WWW的chat程序就是通过信息交换来实现通信。

如果进程P和Q需要通信,他们之间要有通信线路(communication link).这里不关心线路的物理实现只讨论逻辑实现。下面是一些逻辑线路和接收/发送操作的方法:

  • 直接或间接通信
  • 同步或异步通信

下面研究这些相关问题

1.命名

需要通信的进程必须有一个方法以互相引用,他们可使用直接或间接通信。

直接通信:每个进程必须明确的命名通信的接受者或发送者,定义如下:

  • send(P,message)发送信息到进程P
  • receive(Q,message)接收来自Q的消息

这种方案的通信线路具有以下属性:

  • 在需要通信的每对进程之间自动建立线路。进程仅需要知道相互通信的标识符。
  • 一个线路仅与两个进程相关
  • 每对进程之间只有一个线路

这种方式展示了对称寻址,即发送和接收进程必须命名对方以便通信。

这种方案的一种变形采用非对称寻址即只要发送者命名接受者,定义如下:

  • send(P,message)发送消息到进程P
  • receive(id,message)接收来自任何进程的消息,变量id设置成与其通信的进程名称

对称和非对称寻址的缺点是限制了进程定义的模块化

间接通信,通过邮箱或端口发送和接收消息。 
邮箱可以抽象为一个对象,进程可以向其中存放消息,也可以从中删除消息,每个邮箱有唯一的标识符。一个进程可能通过许多不同的邮箱与其他进程通信。但两个进程仅在其共享至少一个邮箱时可以互相通信。

  • send(A,message)发送一个消息到邮箱A
  • receive(A,message)接收来自邮箱A的消息

对于这种方案,通信线路有如下属性:

只有在两个进程共享至少一个邮箱时可以互相通信

一个线路可以与两个以上的进程相关联

两个进程之间可有不同的线路,每个线路对应一个邮箱

2.同步

消息传递可以是阻塞或非阻塞——也称为同步或异步。

  • 阻塞 send: 发送进程阻塞,直到消息被接收进程或邮箱所接收。
  • 非阻塞 send:发送进程发送消息并再继续操作。
  • 阻塞 receive: 接收者阻塞,直到有消息可用。
  • 非阻塞 receive:接收者收到一个有效消息或空消息。

send和receive可以是阻塞或非阻塞的。当都阻塞时,则接受者和发送者之间就有一个集合点(rendezvous)。当使用阻塞send和receive时,如何解决生产者和消费者问题就不在重要了。生产者仅需要调用阻塞send()并等待,直到消息被送到进程或邮箱。同样的,当消费者调用receive()时,发生阻塞直到有一个消息可用。

3.缓冲

不管进程是直接的还是间接的通信进程所交换的消息都驻留在临时队列中,队列实现有三种方法

    • 零容量:队列的最大长度为0.线路中不能有消息处于等待,对于这种情况,消息必须阻塞发送,直到接受者接收到消息。
    • 有限容量:最多有n个消息驻留在其中,如线路满,阻塞发送者
    • 无限容量
时间: 2024-10-07 05:06:35

操作系统概念 进程概述的相关文章

操作系统之进程篇(1)

1.进程介绍: 1.1 进程模型: 进程是一个程序的实际执行,包含了程序计数器的状态,寄存器和变量等等! 程序可以看成是一个状态的序列,程序在不同时刻呈现出不同的状态,而这种状态的前后交替过程可以看成是程序的执行过程.概念上来说,每个程序有自己的虚拟CPU,但在现实中CPU在不同的进程间来回切换,又称这种切换为伪并行! 进程和程序差别看似微小,实际上却是十分精妙; 可以将计算机执行程序的过程看成一次有趣的烹饪过程.食谱就是程序,厨师就是CPU,而食材是输入,得到的输出是鲜美可口的美食. 当厨师在

我的操作系统复习——进程(下)

上一篇博客是复习操作系统进程篇的上篇,包括进程状态.PCB.进程控制等——我的操作系统复习——进程(上),本篇博文是进程篇的下篇,开始复习进程同步.进程通信,以及重要的线程概念. 一.进程同步 什么是同步?同步就是说一个任务要等另一个执行完毕才能继续执行,而不是同时执行.我们都知道,进程有异步性,这种性质会导致操作系统的混乱.进程同步,指的是进程之间的执行次序的管理,就是为了解决进程异步性的这种混乱. (1)直接制约和间接制约. 进程之间有两种制约关系.分别是直接制约和间接制约.直接制约指的是进

操作系统:进程管理和IO控制

一.进程管理 进程管理包括进程控制,进程调度,进程同步与通信,死锁控制四个内容. (一)进程控制 进程是操作系统中运行的基本单位,包括程序段,数据段和进程控制段.操作系统通过进程控制块(PCB)管理进程.每一个PCB唯一标示一个进程.它存储进程的PID,UID,当前状态等信息,以及进程执行某一时刻的寄存器值,并且指向进程的数据段和程序段.OS把所有PCB链接为一个链表. 进程在刚刚被创建时出于new状态.OS负责申请一块存储空间作为该进程的PCB,在其中填上进程的信息,标示为ready,链接到P

操作系统之进程管理

本章要点: 基础:进程描述及控制 策略:进程调度 实现:互斥与同步 避免:死锁与饥饿 进程定义: 可并发执行的程序,在一个数据集合上的运行过程: 申请/拥有资源的最小单位: 程序定义:静态概念,是指令和数据的集合,可长期存储: 进程与程序对应关系: 一个程序可以对应一个进程或者多个进程: 一个进程可以对应一个程序,或者一段程序: 进程的特征: 1.动态性: 2.并发性: 3.独立性: 4.异步性: 引入进程带来的问题: 增加了空间开销:为进程建立数据结构, 额外的时间开销:管理和协调.跟踪.填写

信管备考知识点精讲·操作系统之进程与线程

信息系统管理工程师是全国计算机技术与软件专业技术资格考试(简称计算机软件资格考试)中的一个中级考试.信息系统管理工程师考试要求考生掌握计算机系统.操作系统.数据库.计算机网络.信息化和信息系统等相关知识内容.信息系统管理工程师考试要求掌握的内容宽且多,备考期间哪些内容是需要重点掌握的呢?下面跟着希赛软考学院来学习信息系统管理工程师操作系统章节有关进程与线程需要重点掌握的内容. 信息系统管理工程师备考知识点精讲之进程与线程  1.进程 (1)进程概念 进程是程序在一个数据集合上运行的过程,它是系统

【操作系统】进程管理

进程管理 进程的基本概念 程序的顺序执行及其特征 程序的顺序执行:仅当前一操作(程序段)执行完后,才能执行后续操作. 程序顺序执行时的特征:顺序性,封闭性,可再见性. 前趋图 前趋图(Precedence Graph)是一个有向无循环图,记为DAG(Directed Acycilc Graph),用于描述进程之间执行的前后关系.图中的每一个节点可用于描述一个程序段或进程,乃至一条语句.结点间的有向边则用于表示两个结点之间存在的偏序(Partial Order)或前趋关系(Precedence R

深入理解Linux操作系统守护进程的意义

Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程(daemons)来执行的.守护进程是生存期长的一种进程.它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.他们常常在系统引导装入时启动,在系统关闭时终止.linux系统有很多守护进程,大多数服务器都是用守护进程实现的.同时,守护进程完成许多系统任务,比如,作业规划进程crond.打印进程lqd等.有些书籍和资料也把

操作系统基础-进程

进程的创建 四种主要的事件导致进程的创建: 系统初始化 正在运行的进程发出系统调用,创建一个活多个进程 用户请求创建一个新进程 一个批处理作业的初始化 在所有的情形中,新进程都是由于一个以存在的进程执行了一个用与创建进程的系统调用而创建的. Unix 进程的创建: fork(系统调用)--> 创建一个与系统调用相同的副本 --> 子进程执行execve或一个类似的系统调用 --> 修改其存储映像并运行一个新的程序. 在调用fork后,父进程和子进程拥有相同的存储映像,同样的环境字符串,同

【操作系统】进程描述与控制

前言: 开发操作系统是为了给应用程序提供一个方便.安全.一致的访问接口,以屏蔽硬件的复杂性.我们可以将操作系统理解为资源的统一抽象表示,可以被应用程序请求和访问.资源包括内存,文件等,一旦操作系统为应用程序创建了这些资源的抽象表示,就必须管理它们的使用.现代操作系统采用进程来管理应用程序的执行. 进程的概念: 1.一个具有以下特征的活动单元:一组指令序列的执行.一个当前状态和相关的系统资源集. 2.能分配给处理器并由处理器执行的实体. 3.一个正在计算机上执行的程序实例. 进程的组成: 进程由程