管理系统

操作系统原理(二),进程、线程

2018-05-04  本文已影响209人  dy2903

现代操作系统比如,Linux,Windows等,都是支持“多任务”的操作系统。所谓多任务,指的就是操作系统可以同时运行多个任务。也就是在同一台电脑上,可以同时上网、听歌、使用Word,在过去单核的CPU上都已经可以支持多任务,实现的方式是操作系统让各个任务轮流交替执行。,比如任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒,因为CPU执行速度非常块,我们感觉到所有任务都是并发处理。

到了多核CPU时代,由于任务数量还是远远多过CPU的核心数量,所以操作系统也会自动把多任务轮流调度到每个核心上执行。

何为“进程(Process)”,对操作系统来说一个任务就是一个进程,比如打开了迅雷,而进程有可能不止同时干一件事,比如迅雷可以同时下载多个链接,浏览器可以开多个页面等。把进程内的这些“子任务”称为线程(Thread)。

由于每个进程至少要干一件事,所以,一个进程至少有一个线程,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换。

所以现在如果要执行多个任务有两种解决方案。

总结一下,多任务有三种方式

引用知乎上的一个比喻:

1.单进程单线程:一个人在一个桌子上吃菜。
2.单进程多线程:多个人在同一个桌子上一起吃菜。所以多个人同时吃一道菜的时候容易发生争抢,也就是说资源共享就会发生冲突争抢
3.多进程单线程:多个人每个人在自己的桌子上吃菜。

对于Windows来说,加一张桌子开销很大,所以 Windows 鼓励大家在一个桌子上吃菜,所以需要面对线程资源争抢与同步的问题。
对Linux而言,开一张新桌子开销很小,所以可以尽可能多开新桌子,但是在不同桌子上说话不方便,所以需要研究进程间的通信。

那么什么时候适合使用多任务呢?需要执行耗时操作的时候。比如发起一条网络请求,因为网速的原因,服务器不会立刻响应我们 ,如果不开多任务,则主任务会阻塞住,从而影响体验。

现在的服务器的CPU一般会有多个核心。

总结:


image.png

下面详细的介绍一下进程和线程

进程

无操作系统的时候,程序只能顺序执行,当引入了多任务操作系统以后,如果程序之间没有依赖关系 ,则可以并发执行

我们可以将程序的一次执行称为一个进程既然进程是动态的,所以它从创建到结束有一个完整的生命周期,而且CPU等资源是非常有限的,不是所有进程就可以立即占用CPU资源的,所以我们需要一个数据结构记录和描述进程处于什么样的阶段,这样操作系统才可以全局调度。

为了使进程可以并发执行,为进程引入了进程控制块,即进程控制块(Processing Control Block)。这个数据结构记录了进程的相关信息比如要运行的指令地址,进程的状态,CPU暂存器等。也就是说操作系统其实是根据PCB的信息来对并发进程进行控制和管理的。如果没有PCB的话,系统无法感知到进程,所以PCB是进程存在的唯一标志。

那么PCB主要包含什么呢?

整个计算机系统中存在多个PCB,为了方便查找,将具有相同状态的PCB通过链表的形式组成一个队列 。而且因为PCB会经常用到,所以常驻内存

进程的状态

进程具有三种基本的状态

多进程

Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程可以很容易拿到父进程的ID。

有了fork调用,一个进程在接到新任务时就可以复制出一个子进程来处理新任务,常见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。

进程通信

进程通信指的是进程之间交互信息或者数据。Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信,比如

image.png

线程

进程是运行着的程序,已经可以实现多个进程之间的并发了,但是若进程是资源的持有者,每次进程的切换都意味着资源的获得和释放,对性能消耗太大了。所以引入“更轻量的进程”也就是线程。

也就是说进程只作为资源的持有者,然后开若干个线程进行并行处理,同一个进程中的线程共享此进程的资源,只有从一个进程中的线程切换到另一个进程中才会引起进程的调度。

总之,进程是资源的拥有者,而线程变成了独立调度的基本单位,线程本身不拥有资源,只是共享其所在的进程的资源。

进程关注的是内存的占有,每个进程所能访问的内存都是圈好的,而线程作为进程的一部分,扮演的角色就是怎么利用中CPU去运行代码,所以关注的是中央处理器的运行,而不是内存等资源的管理。

线程的实现方式

线程有两种实现方式

对于用户级线程的实现需要通过中间系统比如运行时系统和内核控制线程。

所谓运行时系统指的是管理和控制线程的函数集合,

第二种方法是通过轻型进程作为中间系统,这些轻型进程可以通过系统调用来获得内核服务,若干个轻型进程形成线程池,而用户级线程运行的时候,只要从池子里面取一个轻型进程连接上,就可以获得如内核进程一样的服务了。

image.png

多线程

多任务可以由多进程完成,也可以由一个进程内的多线程完成。由于任何进程默认就会启动一个线程,我们把该线程称为主线程,主线程又可以启动新的线程

多线程和多进程最大的不同在于,多进程中,同一个数据,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个数据都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。所以仍然可以给临界区代码加一把,因此其他线程不能同时执行此代码,只能等待,直到锁被释放后,获得该锁以后才能改。由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程

锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处是

进程VS线程

多进程和多线程是多任务最主要的两种方式。要实现多任务,通常会使用计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。
多进程模式:

对多线程模式而言,多线程模式通常比多进程快一点,但是也快不到哪去。而且,多线程模式最大的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。在Windows下,多线程的效率比多进程要高,所以微软的IIS服务器默认采用多线程模式。由于多线程存在稳定性的问题,IIS的稳定性就不如Apache。

其实不管是多线程还是多进程,一旦数量上去了,效率都不会太高。如果做作业,先花1小时做语文作业,做完了,再花1小时做数学作业,这样,依次全部做完,一共花5小时,这种方式称为单任务模型,或者批处理任务模型。

然后到了多任务模型,做1分钟语文,再切换到数学作业,做1分钟,再切换到英语,以此类推,只要切换速度足够快,这种方式就和单核CPU执行多任务是一样的了,看上去就正在同时写5科作业。

但是注意,切换是要付出代价的。从语文切到数学,要先收拾桌子上的语文书(保存现场),然后,打开数学课本(这叫准备新环境)。
操作系统在切换也一样,要先保存当前执行的现场环境(CPU寄存器状态、内存页等),然后,把新任务的执行环境准备好(恢复上次的寄存器状态,切换内存页等),才能开始执行。如果有几千个任务同时进行,操作系统可能就主要忙着切换任务,然后硬盘狂响,点窗口无反应,系统处于假死状态。

image.png

异步IO

可以把任务分为计算密集型和IO密集型。

那么因为CPU和IO的速度有天壤之别,所以如果一个任务在执行的过程中大部分时间都在等待IO操作,最好引入多进程模型或者多线程模型来支持多任务并发执行。
为多个用户服务,每个用户都会分配一个线程,如果遇到IO导致线程被挂起,其他用户的线程不受影响。

这样虽然解决了并发问题,但是线程数量过多,CPU的时间就花在线程切换上了,所以引入了异步IO,如果充分利用的异步IO,就可以用单进程单线程模型来执行多任务,这种全新的模型称为事件驱动模型,Nginx就是支持异步IO的Web服务器。在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分利用多核CPU,这样总的进程数量并不多,操作系统调度非常高效。

那么什么是异步IO呢?

所谓异步IO指的是当需要执行一个耗时的IO操作时,它只发出IO指令,并不等待IO结果,然后就去进入下一轮消息处理。一段时间后,当IO返回结果时,再通知CPU直接获取IO操作结果

异步IO模型需要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”这一过程,也就是说在“发出IO请求”到收到“IO完成”的这段时间里,异步IO模型的主线程并没有休息,而是在消息循环中继续处理其他消息,而不是像同步IO模型下,主线程只能挂起。这样,一个线程就可以同时处理多个IO请求,并且没有切换线程的操作。

image.png
上一篇 下一篇

猜你喜欢

热点阅读