操作系统进程管理

进程和线程:

一、进程、并发、pcb的概念

程序和进程

程序:编译好的二进制文件,只占用磁盘空间。(死的)

进程:活跃的程序 ,占用内存、cpu。能独立运行且是资源分配的基本单位。

运行的程序是一个进程。同一个程序可以加载为不同的进程,彼此之间不影响。

并发和并行

并发:一个时间段有多个进程,处于已启动运行,到运行完毕的阶段。但在任一时刻,只有一个进程在运行。

并行:在任一时刻有多个进程在运行(比如:多核CPU)。

对于多处理机,并发执行的程序可被分配到多个处理机上并行执行。

进程控制块pcb

内存中有多个进程,为了方便管理,Kernel为每个进程都建立一个PCB(进程控制块,本质结构体)来保存与其相关的信息。进程创建:生成该进程的PCB,进程终止,回收它的PCB。进程控制块存在于进程的高1G空间,也就是内核空间中。**PCB进程控制块:本质:结构体。**内部有许多成员,比如一个指针,指向文件描述符表(在文件管理中出现过)

PCB中保存了进程的所有信息,将这些信息可以分为几大类:

​ 1、进程标识信息。比如进程ID、所属用户ID、所属组ID、父进程ID等。

​ 2、进程控制信息。比如进程调度信息、进程通信机制等。

​ 3、进程资源信息。比如打开的文件、进程地址空间等。

​ 4、cpu状态信息。用来进程被中断时保护现场。

处于相同状态的进程,他们对应的PCB们会串成一个链表或是索引表,比如

就绪状态一串PCB,各种等待状态一串PCB…这是由OS管理的

在这里插入图片描述
进程的生命周期划分

创建——>就绪——>运行——>等待(条件不满足就等着,被自己催眠)——>被唤醒(条件满足了就醒了,被别的进程或操作系统叫醒)——>就绪——>运行——>被抢占(高优先级进程插队了,或者当前进程被分配的执行时间片用完)——>就绪——>结束(归还资源,结束分为:正常结束,出错自愿退出,出错强制退出,被杀掉)

三状态进程模型(根据CPU):运行、就绪、等待、创建、退出

挂起进程模型(根据存储):运行、就绪、就绪挂起、等待、等待挂起、创建、退出

等待挂起:进程在外存中等待事件的出现

就绪挂起:进程在外存中就绪,只要进入内存即可运行

挂起:把进程从内存转到外存

从等待到等待挂起:没有进程处于就绪状态,或就绪进程需要更多内存

从就绪到就绪挂起:为了给高优先级等待进程提供内存空间,将低优先级就绪进程转入外存

从运行到就绪挂起:高优先级等待挂起进程进入就绪状态后,正运行的程序放入外存

激活:把进程从外存倒回内存

从就绪挂起到就绪:没有就绪进程或挂起就绪进程优先级高于就绪进程

从等待挂起到等待:当一个进程释放足够内存,并有高优先级等待挂起进程

状态队列:

由OS维护一组队列,表示系统中所有进程的当前状态

不同队列表示不同状态:包括若干个就绪队列以及若干个等待队列

根据进程状态的变化,PCB切换到相应队列。

二、线程

为什么引入线程:为了支持进程内部的并发

比如某个MP3播放软件进程,需要从MP3音频文件读数据(IO),解压数据(CPU),送到声卡播放,问题来了:播放声音是否连贯,另外IO和CPU操作不是并发的,会影响资源的使用效率。这三个模块分成三个进程实现,则存在进程通信和共享数据的问题,且开销大。因此引入了线程!

线程:可以并发执行,共享地址空间和文件等资源。线程是进程的一部分,描述指令流执行的状态,它是进程中的指令执行流的最小单元,是CPU调度的基本单位。

缺点:一个线程崩溃会导致进程其他的所有线程崩溃

有了线程之后,跟指令流相关的内容就不放在进程地址空间中。另外堆栈变成了线程各自的堆栈。线程控制块 TCB中保存和执行相关的信息
在这里插入图片描述

进程 VS 线程

  1. 进程是资源分配单位,线程是CPU调度单位

  2. 进程拥有完整的资源平台,线程只独享指令流执行的必要资源(寄存器、栈)

  3. 线程有就绪、等待、运行三种基本状态和状态之间的转换关系

  4. 线程额可以减少并发执行的时空开销。线程切换比进程切换块,线程的创建和终止比进程短,由于同一进程的各线程

线程的三种实现方式

  • 用户线程:在用户空间实现:由线程库函数完成线程的管理。每个进程有私有的线程控制块列 TCB 列表,TCB由线程库函数维护。不支持基于线程的CPU抢占。每个线程的时间片较少。
  • 内核线程:在内核中实现:由内核维护PCB和TCB,系统调用完成线程的管理。线程执行系统调用而被阻塞不影响其他线程。以线程位单位进行CPU时间分配,多线程的进程可获得更多CPU时间
  • 轻权进程(Linux):将用户线程和内核线程结合起来。在内核中实现,支持用户线程。一个进程可有一个或多个轻量级进程,每个轻权进程由一个单独的内核线程来支持。

在这里插入图片描述

三、进程控制

3.1 进程切换

进程切换(上下文切换):暂停当前运行进程,从运行状态变成其他状态,调度另一个进程从就绪状态变成运行状态。其中进程PCB记录了

在这里插入图片描述

3.2 进程创建

Windows下:创建进程API:CreateProcess

Unix下:创建进程的系统调用:fork+exec

  • fork()把父进程复制一个子进程,PID不同,执行内容相同(对子进程分配内存,复制了父进程的内存和CPU寄存器),父进程fork返回子进程的PID,子进程fork返回0

  • fork改进:vfork():创建进程时,不再创建一个同样的内存映像,子进程立刻调用exec()以减少内存拷贝的开销

  • exec()用新程序来重写子进程,PID不变

int pid = fork();
if(pid==0){
    
     
	//若创建子进程,进入一段代码
	exec("program",argc,argv0,argv1);
}else{
    
    
	//父进程执行代码

3.3 进程加载

允许进程加载一个完全不同的程序,并从main开始执行(比如exec)。如果加载成功,则进程的堆栈和代码段完全重写。主要工作是不同格式的可执行文件处理不同

3.4 进程等待和退出

wait()系统调用,用于父进程等待子进程的结束。

  • 子进程存活,父进程进入wait状态,子进程结束通过exit()向父进程返回一个值,唤醒父进程,父进程通过wait()接受并处理返回值

exit()进程结束执行时调用exit(),完成进程资源回收

  • 作为子进程的退出结果,返回给父进程
  • 关闭文件等资源,释放内存,释放大部分进程相关的内核数据结构
  • 检查父进程是否存活:若父进程活着:保留结果的值,直到父进程需要,子进程进入僵尸状态。否则,释放所有的数据结构和进程结果

在这里插入图片描述

3.5 僵尸进程和孤儿进程(转载)

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称为僵尸进程。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位 置,记载该进程的退出状态等信息供其他进程收集。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD 信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了, 那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是 为什么系统中有时会有很多的僵尸进程。

unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放。 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

**任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。**这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

僵尸进程危害场景:

例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。

3.6 其他进程控制的系统调用

优先级控制:

  • nice()指定进程的初始优先级,Unix中进程优先级会随着执行时间而衰减。

进程调试支持:

  • ptrace()允许一个进程控制另一个进程的执行,设置断点、查看寄存器等。
    ** 定时:**
  • sleep()让进程在定时器的等待队列中等待

四、杂七杂八

进程和进程有隔离,线程和线程共享

单道系统、多道系统、分时系统

单道系统:排队运行。A阻塞(比如:IO去了),B只能等待,CPU空闲。(被淘汰了)

多道系统:内存中有多道程序。A阻塞,B运行,排队。

时钟中断:让进程强制退出资源占用。(操作系统的中断处理函数调度)

分时系统:在内存中轮转运行。用多路卡,使主机以很快的速度周期性扫描多个终端,接收多个用户的数据。

虚拟、时分复用、空分复用

虚拟:将一条物理实体变为若干个逻辑对应物。

时分复用:利用某设备为A服务的空闲时间,服务B。(比如:虚拟机)

空分复用:利用存储器的空闲空间,分区域存放和运行其他多道程序。

虚拟内存:大程序在小空间运行时,只部分调入内存,完成后调出,再调入其他部分。

将宽频信道划分为多个窄频信道

异步和进程同步机制

异步:进程走走停停,以不可预知的速度进行。

进程同步机制:让作业经过多次运行,都会获得完全相同的结果。

理实体变为若干个逻辑对应物。

时分复用:利用某设备为A服务的空闲时间,服务B。(比如:虚拟机)

空分复用:利用存储器的空闲空间,分区域存放和运行其他多道程序。

虚拟内存:大程序在小空间运行时,只部分调入内存,完成后调出,再调入其他部分。

将宽频信道划分为多个窄频信道

异步和进程同步机制

异步:进程走走停停,以不可预知的速度进行。

进程同步机制:让作业经过多次运行,都会获得完全相同的结果。

转自:https://blog.csdn.net/weixin_43206570/article/details/105210308

进程和线程:

一、进程、并发、pcb的概念

程序和进程

程序:编译好的二进制文件,只占用磁盘空间。(死的)

进程:活跃的程序 ,占用内存、cpu。能独立运行且是资源分配的基本单位。

运行的程序是一个进程。同一个程序可以加载为不同的进程,彼此之间不影响。

并发和并行

并发:一个时间段有多个进程,处于已启动运行,到运行完毕的阶段。但在任一时刻,只有一个进程在运行。

并行:在任一时刻有多个进程在运行(比如:多核CPU)。

对于多处理机,并发执行的程序可被分配到多个处理机上并行执行。

进程控制块pcb

内存中有多个进程,为了方便管理,Kernel为每个进程都建立一个PCB(进程控制块,本质结构体)来保存与其相关的信息。进程创建:生成该进程的PCB,进程终止,回收它的PCB。进程控制块存在于进程的高1G空间,也就是内核空间中。**PCB进程控制块:本质:结构体。**内部有许多成员,比如一个指针,指向文件描述符表(在文件管理中出现过)

PCB中保存了进程的所有信息,将这些信息可以分为几大类:

​ 1、进程标识信息。比如进程ID、所属用户ID、所属组ID、父进程ID等。

​ 2、进程控制信息。比如进程调度信息、进程通信机制等。

​ 3、进程资源信息。比如打开的文件、进程地址空间等。

​ 4、cpu状态信息。用来进程被中断时保护现场。

处于相同状态的进程,他们对应的PCB们会串成一个链表或是索引表,比如

就绪状态一串PCB,各种等待状态一串PCB…这是由OS管理的

在这里插入图片描述
进程的生命周期划分

创建——>就绪——>运行——>等待(条件不满足就等着,被自己催眠)——>被唤醒(条件满足了就醒了,被别的进程或操作系统叫醒)——>就绪——>运行——>被抢占(高优先级进程插队了,或者当前进程被分配的执行时间片用完)——>就绪——>结束(归还资源,结束分为:正常结束,出错自愿退出,出错强制退出,被杀掉)

三状态进程模型(根据CPU):运行、就绪、等待、创建、退出

挂起进程模型(根据存储):运行、就绪、就绪挂起、等待、等待挂起、创建、退出

等待挂起:进程在外存中等待事件的出现

就绪挂起:进程在外存中就绪,只要进入内存即可运行

挂起:把进程从内存转到外存

从等待到等待挂起:没有进程处于就绪状态,或就绪进程需要更多内存

从就绪到就绪挂起:为了给高优先级等待进程提供内存空间,将低优先级就绪进程转入外存

从运行到就绪挂起:高优先级等待挂起进程进入就绪状态后,正运行的程序放入外存

激活:把进程从外存倒回内存

从就绪挂起到就绪:没有就绪进程或挂起就绪进程优先级高于就绪进程

从等待挂起到等待:当一个进程释放足够内存,并有高优先级等待挂起进程

状态队列:

由OS维护一组队列,表示系统中所有进程的当前状态

不同队列表示不同状态:包括若干个就绪队列以及若干个等待队列

根据进程状态的变化,PCB切换到相应队列。

二、线程

为什么引入线程:为了支持进程内部的并发

比如某个MP3播放软件进程,需要从MP3音频文件读数据(IO),解压数据(CPU),送到声卡播放,问题来了:播放声音是否连贯,另外IO和CPU操作不是并发的,会影响资源的使用效率。这三个模块分成三个进程实现,则存在进程通信和共享数据的问题,且开销大。因此引入了线程!

线程:可以并发执行,共享地址空间和文件等资源。线程是进程的一部分,描述指令流执行的状态,它是进程中的指令执行流的最小单元,是CPU调度的基本单位。

缺点:一个线程崩溃会导致进程其他的所有线程崩溃

有了线程之后,跟指令流相关的内容就不放在进程地址空间中。另外堆栈变成了线程各自的堆栈。线程控制块 TCB中保存和执行相关的信息
在这里插入图片描述

进程 VS 线程

  1. 进程是资源分配单位,线程是CPU调度单位

  2. 进程拥有完整的资源平台,线程只独享指令流执行的必要资源(寄存器、栈)

  3. 线程有就绪、等待、运行三种基本状态和状态之间的转换关系

  4. 线程额可以减少并发执行的时空开销。线程切换比进程切换块,线程的创建和终止比进程短,由于同一进程的各线程

线程的三种实现方式

  • 用户线程:在用户空间实现:由线程库函数完成线程的管理。每个进程有私有的线程控制块列 TCB 列表,TCB由线程库函数维护。不支持基于线程的CPU抢占。每个线程的时间片较少。
  • 内核线程:在内核中实现:由内核维护PCB和TCB,系统调用完成线程的管理。线程执行系统调用而被阻塞不影响其他线程。以线程位单位进行CPU时间分配,多线程的进程可获得更多CPU时间
  • 轻权进程(Linux):将用户线程和内核线程结合起来。在内核中实现,支持用户线程。一个进程可有一个或多个轻量级进程,每个轻权进程由一个单独的内核线程来支持。

在这里插入图片描述

三、进程控制

3.1 进程切换

进程切换(上下文切换):暂停当前运行进程,从运行状态变成其他状态,调度另一个进程从就绪状态变成运行状态。其中进程PCB记录了

在这里插入图片描述

3.2 进程创建

Windows下:创建进程API:CreateProcess

Unix下:创建进程的系统调用:fork+exec

  • fork()把父进程复制一个子进程,PID不同,执行内容相同(对子进程分配内存,复制了父进程的内存和CPU寄存器),父进程fork返回子进程的PID,子进程fork返回0

  • fork改进:vfork():创建进程时,不再创建一个同样的内存映像,子进程立刻调用exec()以减少内存拷贝的开销

  • exec()用新程序来重写子进程,PID不变

猜你喜欢

转载自blog.csdn.net/ganxiwu9686/article/details/107200336