操作系统学习——进程与线程

2021/8/8 7:08:07

本文主要是介绍操作系统学习——进程与线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

摘要

主要是详细的讲述进程和线程的相关的基础知识。

 操作系统中最核心的概念就是进程,进程是对正在运行中的程序的一个抽象。操作系统的其他所有内容都是围绕着进程展开的。进程是操作系统提供的最古老也是最重要的概念之一。即使可以使用的CPU只有一个,它们也支持﹐(伪)并发操作。它们会将一个单独的CPU抽象为多个虚拟机的CPu可以说:没有进程的抽象,现代操作系统将不复存在。

 在许多多道程序系统中,CPU 会在进程间快速切换,使每个程序运行几十或者几百毫秒。然而,严格意义来说,在某一个瞬间,CPU只能运行一个进程,然而我们如果把时间定位为1秒内的话,它可能运行多个进程。这样就会让我们产生并行的错觉。有时候人们说的伪并行就是这种情况,以此来区分多处理器系统(该系统由两个或多个CPU来共享同一个物理内存)

伪并行:伪并行是指单核或多核处理器同时执行多个进程,从而使程序更快.通过以非常有限的时间间隔在程序之间快速切换CPU,因此会产生并行感。缺点是CPU时间可能分配给下一个进程,也可能不分配给下一个进程。

进程模型

总结一句话是:进程是计算机系统分配资源的最小单位。

在进程模型中,所有计算机上运行的软件,通常也包括操作系统,被组织为若干顺序进程(sequentialprocesses),简称为进程(process)。一个进程就是一个正在执行的程序的实例,进程也包括程序计数器、寄存器和变量的当前值。从概念上来说,每个进程都有各自的虚拟CPU,但是实际情况是CPU会在各个进程之间进行来回切换。

 在上图中,这4道程序被抽象为4个拥有各自控制流程〈即每个自己的程序计数器)的进程,并且每个程序都独立的运行。当然,实际上只有一个物理程序计数器,每个程序要运行时,其逻辑程序计数器会装载到物理程序计数器中。当程序运行结束后,其物理程序计数器就会是真正的程序计数器,然后再把它放回进程的逻辑计数器中。

从下图我们可以看到,在观察足够长的一段时间后,所有的进程都运行了,但在任何一个给定的瞬间仅有一个进程真正运行。

 因此,当我们说一个CPU只能真正一次运行一个进程的时候,即使有﹖个核(或CPU),每一个核也只能一次运行一个线程。

由于CPU 会在各个进程之间来回快速切换,所以每个进程在CPU中的运行时间是无法确定的。并且当同一个进程再次在CPU中运行时,其在CPU内部的运行时间往往也是不固定的。进程和程序之间的区别是非常微妙的,但是通过一个例子可以让你加以区分:想想一位会做饭的计算机科学家正在为他的女儿制作生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原谅∶面粉、鸡蛋、糖、香草汁等。在这个比喻中,做蛋糕的食谱就是程序、计算机科学家就是CPU、而做蛋糕的各种原谅都是输入数据。进程就是科学家阅读食谱、取来各种原料以及烘焙蛋糕等一系例了动作的总和。

这里的关键思想是认识到一个进程所需的条件,进程是某一类特定活动的总和,它有程序、输入输出以及状态。单个处理器可以被若干进程共享,它使用某种调度算法决定何时停止一个进程的工作,并转而为另外一个进程提供服务。另外需要注意的是,如果一个进程运行了两遍,则被认为是两个进程。那么我们了解到进程模型后,那么进程是如何创建的呢?

进程的创建

操作系统需要一些方式来创建进程。下面是一些创建进程的方式:

  • 系统初始化(init)

启动操作系统时,通常会创建若干个进程。其中有些是前台进程(numerous processes),也就是同用户进行交互并替他们完成工作的进程。一些运行在后台,并不与特定的用户进行交互,例如,设计一个进程来接收发来的电子邮件,这个进程大部分的时间都在休眠,但是只要邮件到来后这个进程就会被唤醒。进程运行在后台用来处理一些活动像是e-mail,web网页,新闻,打印等等被称为守护进程(daemons)。大型系统会有很多守护进程。在UNIX中, ps程序可以列出正在运行的进程,在Windows 中,可以使用任务管理器。

  • 正在运行的程序执行了创建进程的系统调用(比如fork)

除了在启动阶段创建进程之外,一些新的进程也可以在后面创建。通常,一个正在运行的进程会发出系统调用用来创建一个或多个新进程来帮助其完成工作。例如,如果有大量的数据需要经过网络调取并进行顺序处理,那么创建一个进程读数据,并把数据放到共享缓冲区中,而让第二个进程取走并正确处理会比较容易些。在多处理器中,让每个进程运行在不同的CPU上也可以使工作做的更快。

  • 用户请求创建一个新进程

在许多交互式系统中,输入一个命令或者双击图标就可以启动程序,以上任意一种操作都可以选择开启一个新的进程,在基本的UNIX系统中运行X,新进程将接管启动它的窗口。在 Windows 中启动进程时,它一般没有窗口,但是它可以创建一个或多个窗口。每个窗口都可以运行进程。通过鼠标或者命令就可以切换窗口并与进程进行交互。

  • 初始化一个批处理工作

最后一种创建进程的情形会在大型机的批处理系统中应用。用户在这种系统中提交批处理作业。当操作系统决定它有资源来运行另一个任务时,它将创建一个新进程并从其中的输入队列中运行下一个作业。从技术上讲,在所有这些情况下,让现有流程执行流程是通过创建系统调用来创建新流程的。该进程可能是正在运行的用户进程,是从键盘或鼠标调用的系统进程或批处理程序。这些就是系统调用创建新进程的过程。该系统调用告诉操作系统创建一个新进程,并直接或间接指示在其中运行哪个程序。

 进程的终止

进程在创建之后,它就开始运行并做完成任务。然而,没有什么事儿是永不停歇的,包括进程也一样。进程早晚会发生终止,但是通常是由于以下情况触发的

  • 正常退出(自愿的)

多数进程是由于完成了工作而终止.当编译器完成了所给定程序的编译之后,编译器会执行一个系统调用告诉操作系统它完成了工作。这个调用在UNIX中是l exit l,在 Windows 中是ExitProcess面向屏幕中的软件也支持自愿终止操作。字处理软件、Internet浏览器和类似的程序中总有一个供用户点击的图标或菜单项,用来通知进程删除它锁打开的任何临时文件,然后终止。

  • 错误退出(自愿的)

进程发生终止的第二个原因是发现严重错误,例如,如果用户执行如下命令:cc foo.c
为了能够编译foo.c但是该文件不存在,于是编译器就会发出声明并退出。在给出了错误参数时,面屏幕的交互式进程通常并不会直接退出,因为这从用户的角度来说并不合理,用户需要知道发生了什么并想要进行重试,所以这时候应用程序通常会弹出一个对话框告知用户发生了系统错误,是需要重试还是退出。

  • 严重错误(非自愿的)

进程终止的第三个原因是由进程引起的错误,通常是由于程序中的错误所导致的。例如,执行了一条非法指令,引用不存在的内存,或者除数是О等。在有些系统比如UNIX中,进程可以通知操作系统,它希望自行处理某种类型的错误,在这类错误中,进程会收到信号(中断),而不是在这类错误出现时直接终止进程。

  • 其他进程杀死(非自愿的)

第四个终止进程的原因是,某个进程执行系统调用告诉操作系统杀死某个进程。在UNIX中,这个系统调用是kill!在Win32中对应的函数是TerminateProcess(注意不是系统调用。

进程的层次结构

在一些系统中,当一个进程创建了其他进程后,父进程和子进程就会以某种方式进行关联。子进程它自己就会创建更多进程,从而形成一个进程层次结构。

  • UNIX进程体系

在UNIX中,进程和它的所有子进程以及子进程的子进程共同组成一个进程组。当用户从键盘中发出一个信号后,该信号被发送给当前与键盘相关的进程组中的所有成员(它们通常是在当前窗口创建的所有活动进程)。每个进程可以分别捕获该信号、忽略该信号或采取默认动作,被信号kill掉。

这里有另一个例子,可以用来说明层次的作用,考虑UNIX在启动时如何初始化自己。一个称为init 的特殊进程出现在启动映像中。当init进程开始运行时,它会读取一个文件,文件会告诉它有多少个终端。然后为每个终端创建一个新进程。这些进程等待用户登录。如果登录成功,该登录进程就执行一个shell 来等待接收用户输入指令,这些命令可能会启动更多的进程,以此类推。因此,整个操作系统中所有的进程都隶属于一个单个以init为根的进程树。

  •  window进程体系

相反,Windows 中没有进程层次的概念,Windows 中所有进程都是平等的,唯一类似于层次结构的是在创建进程的时候,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程。然而,这个令牌可能也会移交给别的操作系统,这样就不存在层次结构了。而在 UNI中,进程不能剥夺其子进程的进程权。

进程和线程的区别与联系

区别:

  • 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位;
  • 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行;
  • 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。进程所维护的是程序所包含的资源(静态资源), 如:地址空间,打开的文件句柄集,文件系统状态,信号处理handler等;线程所维护的运行相关的资源(动态资源),如:运行栈,调度相关的控制信息,待处理的信号集等;
  • 系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。但是进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个进程死掉就等于所有的线程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

联系

  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程;

  • 资源分配给进程,同一进程的所有线程共享该进程的所有资源;

  • 处理机分给线程,即真正在处理机上运行的是线程;

  • 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

协程的原理

来源:https://blog.csdn.net/daaikuaichuan/article/details/82951084

协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。

 协程在子程序内部是可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行

def A():
    print '1'
    print '2'
    print '3'

def B():
    print 'x'
    print 'y'
    print 'z'

假设由协程执行,在执行A的过程中,可以随时中断,去执行B,B也可能在执行过程中中断再去执行A,结果可能是:1 2 x y 3 z。

 协程的特点在于是一个线程执行,那和多线程比,协程有何优势?

    极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显;

    不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
 



这篇关于操作系统学习——进程与线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程