进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。进程是线程的容器。程序是指令、数据及其组织形

式的描述,进程是程序的实体。

进程状态:创建、就绪、运行、阻塞、结束

进程的概念主要有两点:

第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。

第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。

进程特征

➢动态性:进程的实质是程序在多任务系统中的一次执行过程,进程是动态产生,动态消亡的。

➢并发性:任何进程都可以同其他进程一起并发执行

➢独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

➢异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度执行

➢结构特征:进程由程序、数据和进程控制块三部分组成。

➢多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变

CPU组成

CPU由运算器,控制器和寄存器组成,运算器是对数据进行加工处理的部件。它不仅可以实现基本的算术运算,还可以进行基本的逻辑运算,实现逻辑判断的比较及数据传递,移位等操作。控制器是负责从存储器(内存和硬盘)中取出指令,确定指令类型及译码,按时间的先后顺序向其他部件发出控制信号,统一指挥和协调计算机各器件进行工作的部件。寄存器是CPU内部高速独立的暂时存储单元(容量很小)

进程切换

进行进程切换就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。

在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的切换实质上就是被中止运行进程与待运行进程上下文的切换。在进程未占用处理器时,进程的上下文是存储在进程的私有堆栈中。

进程的运行状态

进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程可能具有以下三种基本状态。

1)就绪状态(Ready):进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。

2)运行状态(Running):进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。

3)阻塞状态(Blocked):由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理机分配给该进程,也无法运行

名词

原语(原子操作):操作系统或计算机网络用语范畴。是由若干条指令组成的,用于完成一定功能的一个过。primitive or atomic action 是由若干个机器指令构成的完成某种特定功能的一段程序,具有不可分割性。即原语的执行必须是连续的,在执行过程中不允许被中断

内存(主存):直接给CPU提供存储、高速、低容量、价格贵,不能永久保存数据,断电消失,需要从辅存中重新调入数据。

外存(辅存):给主存提供数据、低速、大容量、价格低,能永久保存数据。所以更高缓存的CPU和更大的内存能够大大提升系统的性能。

常见主存有:CPU的高速缓存,电脑的内存条。

常见辅存有:硬盘、光盘、U盘、磁盘、移动硬盘等

挂起(等待,阻塞)进程:在操作系统中可以定义为暂时被淘汰出内存的进程,机器的资源是有限的,在资源不足的情况下,操作系统对在内存中的程序进行合理的安排,其中有的进程被暂时调离出内存,当条件允许的时候,会被操作系统再次调回内存,重新进入等待被执行的状态即就绪。

进程状态转换


活跃就:是指进程在主存并且可被调度的状态。

静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。

活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。

静止阻塞:是指进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态

进程的创建过程

一旦操作系统发现了要求创建新进程的事件后,便调用进程创建原语Creat()按下述步骤创建一个新进程。

1)申请空白PCB(进程控制块)。为新进程申请获得唯一的数字标识符,并从PCB集合中索取一个空白PCB。

2)为新进程分配资源。为新进程的程序和数据以及用户栈分配必要的内存空间。显然,此时操作系统必须知道新进程所需要的内存大小。

3)初始化进程控制块。PCB的初始化包括:

①初始化标识信息,将系统分配的标识符和父进程标识符,填入新的PCB中。

②初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶。

③初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,对于优先级,通常是将它设置为最低优先级,除非用户以显式的方式提出高优先级要求。

4)将新进程插入就绪队列,如果进程就绪队列能够接纳新进程,便将新进程插入到就绪队列

进程的终止

引起进程终止的事件

1)正常结束

在任何计算机系统中,都应该有一个表示进程已经运行完成的指示。例如,在批处理系统中,通常在程序的最后安排一条Hold指令或终止的系统调用。当程序运行到Hold指令时,将产生一个中断,去通知OS本进程已经完成。

2)异常结束

在进程运行期间,由于出现某些错误和故障而迫使进程终止。这类异常事件很多,常见的有:越界错误,保护错,非法指令,特权指令错,运行超时,等待超时,算术运算错,I/O故障。

3)外界干预

外界干预并非指在本进程运行中出现了异常事件,而是指进程应外界的请求而终止运行。这些干预有:操作员或操作系统干预,父进程请求,父进程终止

进程终止过程

如果系统发生了上述要求终止进程的某事件后,OS便调用进程终止原语,按下述过程去终止指定的进程。

1)根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程状态。

2)若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真。用于指示该进程被终止后应重新进行调度。

3)若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。

4)将被终止的进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。

5)将被终止进程(它的PCB)从所在队列(或链表)中移出,等待其它程序来搜集信息

阻塞唤醒—引起阻塞和唤醒的事件

阻塞

1)请求系统服务

当正在执行的进程请求操作系统提供服务时,由于某种原因,操作系统并不立即满足该进程的要求时,该进程只能转变为阻塞状态来等待,一旦要求得到满足后,进程被唤醒。

2)启动某种操作

当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先使该进程阻塞,以等待该操作完成,该操作完成后,将该进程唤醒。

3)新数据尚未到达

对于相互合作的进程,如果其中一个进程需要先获得另一(合作)进程提供的数据才能运行以对数据进行处理,则是要其所需数据尚未到达,该进程只有(等待)阻塞,等到数据到达后,该进程被唤醒。

4)无新工作可做

系统往往设置一些具有某特定功能的系统进程,每当这种进程完成任务后,便把自己阻塞起来以等待新任务到来,新任务到达后,该进程被唤

唤醒

当被阻塞的进程所期待的事件出现时,如I/O完成或者其所期待的数据已经到达,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup(),将等待该事件的进程唤醒。唤醒原语执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中。

python进程

os.fork()

fork()函数,它也属于一个内建函数,并且只在Linux系统下存在。它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后分别在父进程和子进程内返回。子进程永远返回0,而父进程返回子进程的PID。这样做的理由是,一个父进程可以fork()出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID,子进程只需要调用os.getpid()函数可以获取自己的进程号

#!/user/bin/python

#encoding=utf-8

import os

print (os.getpid())

pid = os.fork() # 创建一个子进程

print (pid)  #子进程id和0

if pid == 0:

  print ('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))

else:

  print ('I (%s) just created a child process (%s).' % (os.getpid(), pid))

"""

执行结果:

[student2018@iZ2zejbxp2btn9jh8knipuZ 20181217]$ python3 demo1.py

27251

27252

0

I (27251) just created a child process (27252).

I am child process (27252) and my parent is 27251.

"""

multiprocessing模块

multiprocessing模块就是跨平台版本的多进程管理包,支持子进程、通信和共享数据、执行不同形式的同步。

它与 threading.Thread类似,可以利用multiprocessing.Process对象来创建一个进程。该进程可以允许放在Python程序内部编写的函数中。

这个模块表示像线程一样管理进程,这个是multiprocessing的核心,它与hreading很相似,对多核CPU的利用率会比threading好的多

创建进程

Multiprocessing模块创建进程使用的是Process类。

Process类的构造方法:

help(multiprocessing.Process)

init(self, group=None, target=None, name=None, args=(), kwargs={})

参数说明:

group:进程所属组,基本不用。

target:表示调用对象,一般为函数。

args:表示调用对象的位置参数元组。

name:进程别名。

kwargs:表示调用对象的字典。

#coding=utf-8

import multiprocessing

def do(n) :

  #获取当前线程的名字

  name = multiprocessing.current_process().name

  print(name,'starting')

  print("worker ", n)

  return

if __name__ == '__main__' :

  numList = []

  for i in range(1,6) :

    p = multiprocessing.Process(target=do, args=(i,))

    numList.append(p)

    p.start()

    #p.join() #p进程,通过join方法通知主进程死等我结束,再继续执行

    print("Process end.")

  for i in numList:

    i.join()#每一个进程执行结束后,才会开始下一次循环

#循环结束了,也就说5个进程全部执行完毕了,然后在执行print语句。

  print(numList)

"""

执行结果:

F:\Faker\python\gloryload\20181217>py -3 demo2.py

Process end.

Process end.

Process end.

Process end.

Process end.

Process-1 starting

worker  1

Process-2 starting

worker  2

Process-3 starting

worker  3

Process-4 starting

worker  4

Process-5 starting

worker  5

[, , , , ]

"""

创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,并用其start()方法启动,这样创建进程比fork()还要简单。

join()方法表示等待子进程结束以后再继续往下运行,通常用于进程间的同步。

注意:

在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的if name == "main":语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要

你可能感兴趣的:(进程)