进程,执行中的程序。进程的概念产生,是因为现代计算机系统允许多个程序调入内存并发执行。
具体来说,进程是执行中的程序,除了程序代码,还包括该程序的当前活动,包括程序计数器的值,处理器的寄存器内容,堆栈段(临时数据,如函数参数,返回地址,局部变量等)和 数据段(全局变量),可能还有堆(进程运行期间动态分配的内存)。
程序本身不是进程,程序是被动实体,而进程是活动实体。同一个程序,可以同时对应多个进程,但进程之间是独立的。进程与程序的关系,就类似对象与类的关系。
1、进程控制块(PCB)
进程在操作系统内用进程控制块来表示。
PCB包含一系列进程信息:
进程状态:新建、就绪、运行、等待、停止
程序计数器:进程要执行的下个指令地址
CPU寄存器
CPU调度信息:优先级等
内存管理信息:
记账信息:CPU时间、实际使用时间、时间界限、记账数据、作业或进程数量
IO状态信息
进程调度
为使CPU使用率达到最大化,操作系统在进程之间快速切换CPU以便用户在程序运行时能与其交互。进程调度负责选择一个可用的进程到CPU上执行。
1、调度队列
调度队列又称为作业队列。作业队列包括就绪队列、设备队列(IO队列)。
驻留在内存中,准备就绪,等待运行的进程保存在就绪队列
等待IO设备的进程列表称为设备队列
队列通常用链表来实现:头节点指向第一个和最后一个PCB;每个PCB指向下一个。
进程首先会进入就绪队列;分配了CPU后,开始执行;顺利的话,一口气最终完成;或者被中断,强行释放CPU,重新回到就绪队列;或者等待特定事件发生(如完成IO请求)。请求IO时,如果有许多进程都进行请求,那么进入设备队列,依次执行。也有的会创建子进程,等待其结束;
2、调度程序
进程调度程序分为长期调度程序和短期调度程序。
长期调度程序负责将进程从缓冲池中调入就绪队列或IO队列;短期程序负责为进程分配CPU,执行。
长期调度程序执行频率不频繁,关键在于在CPU为主和IO为主两个队列的安排中取得平衡;
也有的操作系统会有中期调度程序。负责将中断后的进程从就绪队列中换出,时机成熟时再换入,从中断处再执行。看上去,只有长期、短期调度程序的操作系统,进程一旦被执行,那么一直在就绪队列、CPU之间切换,直到执行完毕,不会中途退出一说。中期调度程序,可以在内存使用过度的情况下,缓解一点。
3、上下文
中断、进程切换,都涉及到上下文。进程上下文用PCB表示,用于中断或切换前的状态保存,到重新执行的状态恢复。上下文切换速度与硬件有关。上下文切换,系统并不能做什么有用的工作。
进程创建
进程在执行过程中,可以创建新进程。那么这个进程称为父进程,新建的进程为子进程。同理,子进程又可以创建自己的子进程,子子孙孙,无穷匮也,形成进程树。
大多数操作系统使用进程标识符(PID)来识别进程。
通常,进程需要资源来完成任务(如CPU时间、内存、文件、IO设备)。在创建子进程时,子进程可能从操作系统获得资源,也可能从父进程获得。限制子进程只能使用父进程的资源可以防止创建进程过多,导致系统超载。
另外,创建之时,初始化数据也由父进程传递给子进程。
子进程创建之后,有2种执行可能:
1)父子进程并发执行
2)父进程等待子进程执行完毕再执行
子进程的地址空间也有2种可能:
1)子进程是父进程的克隆,这样父子有相同的程序和数据
2)子进程装入新程序,另起炉灶
Unix中,通过fork()函数来开辟新进程。fork,分叉的意思。系统调用该函数,返回值为0;父进程调用,返回新进程的PID,这样便于父进程对它进行控制。Windows有类似机制,但Unix是子进程为父进程的复制品(上述情况1?),而WINDOWS则要传很多参数给新进程(上述情况2?)
进程终止
进程可以终止自身;也可以由其他进程调用相关系统服务终止,但通常只能由父进程进行这样的调用,避免360与腾讯互相攻击。
父进程终止子进程有许多理由,如:
1)子进程使用资源太过
2)子进程的任务已out
3)父进程终止
进程通信
进程之间往往需要协作,理由:
1)信息共享
2)并行,提高运算速度(需要多CPU或I/O通道)
3)模块化
4)多任务
进程协作 需要通信机制(interprocess communication,IPC)。有两种基本模式:
1)共享内存
2)消息传递
消息传递处理简单,但速度不如共享内存快,适合交换数据量少,或者用在分布式系统
共享内存速度快,可处理比较多的数据量,不过有同步问题,处理机制较为复杂
两种模式应用都很广泛,并且许多操作系统同时具备这两种模式。
共享内存机制,生产者、消费者模式;
消息传递机制,系统提供,采用邮箱进行中转。这里所说的邮箱,并非我们常说的邮箱,应该是借喻为一种中转机制。
客户机-服务器系统通信
客户机-服务器通信可以使用共享内存、消息传递进行通信,也可以使用Socket、远程过程调用(PRC)和Java的远程方法调用(RMI)。
socket
套接字,通信的端点,由IP地址与端口号组成。一对进程进行网络通信,需要使用一对socket,通常一个做服务器,一个做客户端。服务器通过监听指定端口,收到请求,接受连接,即可完成连接,进行通信矣。凡1024以下的端口,都被认为是实现了标准服务的端口。所以,我们要用的话,可以用大于1024的端口。
RPC
远程过程调用。
类似于IPC机制,但交换的消息有很好的结构,用做传递给函数的参数。跟Socket一样,也是通过端口来进行消息的传送。说不定,就是socket在做底层支持。
RPC的机制,是服务器端在客户端有一个存根,客户端要调用服务器端的方法,就通过这个存根。这个存根代办参数的准备,发送,接收。然后服务器端也有个存根,做相关处理工作。
RPC有几个问题处理:
1)机器之间的数据表示可能有差异
2)保证远程调用的有且只有一次,一是避免重复调用;二是要保证有调用。前者用时间戳;后者用ACK(确认字符),客户端周期性向服务器发出PRC调用,直到收到服务器的ACK回应为止。
RMI
JAVA的RPC机制。
与普通RPC最大的区别就是,它的参数可以是对象。传递的对象如果是引用远程对象,不必多言;如果是本地,需要传递给对方,那么要序列化。
PRC面向过程,RMI面向对象,支持调用远程对象的方法。除此而外,存根为远程对象的代理,驻留于客户机中。