操作系统基础梳理--进程&线程
1、举个栗子
1.1、知乎一形象例子
【摘自知乎】比如说十几年前,马化腾在写QQ,假设他那个时候不懂多进程多线程。然后他就开始写啦,这玩意儿不简单吗,不就是用户输入什么,把信息打包发到另一个用户,再显示出来,卧槽,太简单,2天就能写完一个字符界面的qq!
然后想当然的写出如下伪代码:
while(1):
wait for user input
send user input by UDP/TCP
display incoming messages
end while
这个代码很简单,就是不断地查询用户的输入情况,然后把输的东西发给对方,然后把对方发过来的信息显示到屏幕上。
这么简单,如果当年有python,QQ一天就能发布了。马化腾可开心了,然后就开始调试了。他队友发了一条信息过来,马化腾就在自己电脑面前等啊。。。等啊。。。等啊。。。。丫,怎么还么有信息显示出来啊?猪队友啊?小学生啊?会不会打字啊?呆逼啊,又要单步调试啊?马化腾就开始单步调试了,然后他发现自己的程序卡在了wait for user input上一直不动!对,程序一直在等待输入,如果不输入的话,是没有办法执行后面的任务的!
那怎么办?要不默认如果用户在1秒以内不输入,就跳过input阶段,直接进入后面接收和显示?那也不行,这样会有一定的几率丢失用户输入信息,大爷的!!!
这个时候你就会发现,如果能把输入和显示这两个任务分开,变成两个“程序”,那就太好了。好,那就分成两个程序吧,一个负责输入和发送信息,一个负责读入信息和显示。卧槽,真是太天才了!说干就干!要不了多长时间,两个窗口就诞生了,瞬间觉得自己好牛逼啊!
这个时候,所用的实现方式就是我们说的多进程。这样的方式会产生很多问题,比如:马哥突然发现多开几个聊天窗口的话,会把内存给压榨干净。。。。两个窗口之间交换数据会很麻烦,得走系统层面才能解决。。。。等等等等
这是为什么呢?盖因为多进程的程序,每一个进程都有自己的独立内存空间和资源,相互都是保密的,这就造成了进程之间通信需要通过系统才能完成,无疑会造成资源浪费和时间浪费。
那怎么办?就不能让两个“程序”共享同一片内存空间,他们自己之间交换数据而不通过系统吗?
这时,你才需要一个线程的概念,这就是线程的意义。在一个进程当中,任务需要同时“运行”,不能互相干扰,但是有一些变量,内存,信息之类的又要共享,这才需要到线程。
2、Oracle在不同OS种的进程&线程 区别
Oracle的Unix/Linux版本采用多进程架构,不同的功能模块由不同的进程负责,Windows版本采用单进程多线程架构,所有的模块所在线程处在同一个进程当中。
我们来看一下区别:
- 进程管理。Oracle某个模块挂起了,没有响应,万般无奈你要重起这个模块,Unix平台只要重起这个模块所在的那个进程就可以了,其它进程保持运行,而Windows平台只有一个进程,只能影响所有模块,重启过程中所有模块都不能提供服务。
- 内存空间。每个进程拥有自己的地址空间,如果只有一个进程,所有模块共享/约束在同一空间,如果采用多进程,所有进程地址空间独立,软件申请/管理更多内存的可能和能力变大了。Unix/Linux环境很多运行在小型机,甚至大型机上,单进程显然满足不了需求,Windows运行在PC主机上,对这个没什么要求。
- 线程间通信。因为单进程共享地址空间,进程内线程通信效率很高,不同进程的线程之间通信需要某种IPC手段,效率相比降低。其实Linux平台没有传统意义的“线程”,所有都是进程,我们看到的进程是一个进程组,里面的“线程”就是组成这个进程组的进程。
- 资源管理。单进程中其中一个线程操作文件句柄阻塞了,会影响到其它线程对这个句柄的操作,多进程无此问题。一个进程同时打开的句柄是受限制的,多进程意味着可使用更多资源。
- 运行调度。一个线程Hang了就是这个进程Hang了,一个线程Crash了就是这个进程Crash了,所以多线程要格外小心了,多进程分摊风险更安全。
- 软件开发管理。多进程可以分别交给不同团队开发,多线程分别交给不同团队开发很困难,编译要同步,Debug要同步,进程Crash了是哪个团队的责任往往要花半天时间。等等。
Oracle的这种思维主要是由资源使用决定的,单进程无法满足内存,句柄的使用需求时,只能采用多进程。而Windows微内核结构动态创建进程做得不够好,线程是更好选择,Linux宏内核结构并且线程本来就是通过进程组的方式实现的。
结论是首先由项目规模决定,这是刚需,再者由运行的系统平台决定,非刚需。
2、区别
2.1 通俗理解
进程是应用程序的执行实例。比如说,当你双击的Microsoft Word的图标,你就开始运行的Word的进程。线程是执行进程中的路径。另外,一个过程可以包含多个线程。启动Word时,操作系统创建一个进程并开始执行该进程的主线程。
由于一个进程可以由多个线程,线程可以被认为是“轻量级”的过程。因此,一个线程和一个进程之间的本质区别在于,每一个用来完成的工作。线程用于小任务,而进程用于更多的'重量级'的任务 - 应用基本执行。
一个线程和进程之间的另一个区别是,在同一进程中的线程共享相同的地址空间,而不同的进程没有。因此线程可以读写同样的数据结构和变量,便于线程之间的通信。相反,进程间通信(IPC)很困难且消耗更多资源。
2.2 CPU时间片层面的理解
首先来一句概括的总论:
进程和线程都是一个时间段的描述,是CPU工作时间段的描述。
下面细说背景:
CPU+RAM+各种资源(比如显卡,光驱,键盘,GPS, 等等外设)构成我们的电脑,但是电脑的运行,实际就是CPU和相关寄存器以及RAM之间的事情。
一个最最基础的事实:
CPU太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM和别的挂在各总线上的设备完全是望其项背。那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话就是在CPU看来就是轮流着来。
一个必须知道的事实:
执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。
这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的 程序上下文 。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,等待下一次CPU的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被CPU临幸的运行环境,必须保存。
串联起来的事实:
前面讲过在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文。。。。
========= 重要的东西出现了========
进程和线程就是这样的背景出来的,两个名词不过是对应的CPU时间段的描述,名词就是这样的功能。
进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
线程是什么呢?
进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:
程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。
这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。
到此全文结束,再一个总结:
进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。
2.3 CPU资源分配层面的理解
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。以前进程既是资源分配也是调度的最小单位,后来为了更合理的使用cpu(实际上是cpu性能越来越好),才将资源分配和调度分开,就有了线程。线程是建立在进程的基础上的一次程序运行单位。
- 单进程单线程:一个人在一个桌子上吃菜。
- 单进程多线程:多个人在同一个桌子上一起吃菜。
- 多进程单线程:多个人每个人在自己的桌子上吃菜。
3.总结归纳
以上内容多采自于,从各位大拿处汲取知识,以供学习进步。
https://www.zhihu.com/question/24351439