🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 什么是进程和线程? * **进程**是具有一定独立功能的程序关于某个数据集合上的一次运行活动,**进程是系统进行资源分配和调度的一个独立单位** * **线程**是进程的一个实体,**是CPU调度和分派的基本单位**,它是比进程更小的能独立运行的基本单位 ## 进程和线程的关系是什么? * 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。**线程是操作系统可识别的最小执行和调度单位** * **资源分配给进程,同一进程的所有线程共享该进程的所有资源**。**同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)**。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量 * **处理机分给线程,即真正在处理机上运行的是线程** * 线程在执行过程中,需要协作同步。**不同进程的线程间要利用消息通信的办法实现同步** ## 进程与线程的区别是什么? * 资源:进程是资源分配的基本单位,但线程不拥有资源,线程能访问其所属进程的资源; * 调度:线程是独立调度的基本单位,同一进程中线程的切换不会引起进程的切换,而不同进程间线程的切换会引起进程的切换; * 系统开销:进程的新建和撤销时,系统需要为其分配和回收资源,如内存空间和I/O设备等,开销远大于线程的新建和撤销。进程的切换需要当前进程CPU环境的保护和新进程环境的设置,而线程的切换只需要保存和设置少量的寄存器内容,开销很小。因此,线程的系统开销远低于进程。 * 通信:线程可以直接读写进程数据进行通信,但进程需要IPC(进程间通信技术)进行通信(管道、消息队列、共享内存)。 ## 进程的状态,各个状态之间如何切换? * 就绪:进程已处于准备好运行的状态,即进程已分配到除CPU外的所有必要资源后,只要再获得CPU,便可立即执行 * 执行:进程已经获得CPU,程序正在执行状态 * 阻塞:正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)暂时无法继续执行的状态 ## 怎么选择多进程还是多线程? • CPU密集型:偏重于计算,频繁使用CPU,适合多进程。如机器学习。 • I/O密集型:经常输入输出,适合多线程。如爬虫。 ## 为什么进程上下文切换比线程上下文切换代价高? 进程切换分两步: * 切换页目录以使用新的地址空间 * 切换内核栈和硬件上下文 对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的 切换的性能消耗: * 线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出 * 另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲(processor's Translation Lookaside Buffer (TLB))或者相当的神马东西会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题。 ## 什么是进程(线程)同步? 首先需要明白广义上的“同步”,所谓同步,即在一定条件下应当发生什么事件 如果只有一个进程,那么进程同步指的是这个进程每次运行时的过程是一样的。而现在的操作系统在多道程序设计的背景下,进程基本上是异步的,即每次运行的过程都是不一样的。但是结果可能是一样的。 如果有两个进程A和B(一般是协作关系),那么进程同步的意思是说,两个进程的运行过程是相互制约的。相反,异步就是说两个进程各走各的,不会考虑另一个进程的状态。可想而知,两个异步运行的进程如果是协作关系,那么很有可能出现不协调的情况(竞争条件的出现)。 两个以上进程的同步与两个进程的情况类似。 “进程”也可以换成线程,“互斥”只是为了实现进程同步而使用的一种手段。 ## 进程同步的任务和原则是什么? 进程同步的主要任务:是对多个相关进程在执行次序上进行协调,以使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性 同步机制遵循的原则: * 空闲让进; * 忙则等待(保证对临界区的互斥访问); * 有限等待(有限代表有限的时间,避免死等); * 让权等待,(当进程不能进入自己的临界区时,应该释放处理机,以免陷入忙等状态) ## 协程是什么? * 协程是微线程,在一个线程中执行,执行过程中可以随时中断,由用户控制(进程和线程本质上是系统运行)。执行效率高,减少了线程切换和锁开销。 * 协程失去了标准线程使用多核的能力。**多进程+协程**,既可以利用多核,又能利用协程的高效率。 * 实现:asyncio(异步IO,即不用等待其结束就能进行其他操作),在yield处暂停等待指令。 ## 协程相比线程的优势是什么? **协程执行效率高。** * 协程由用户控制,不需要线程切换开销。与多线程相比,线程数量越多,协程的优势越明显; * 协程不需要锁机制。线程中需要用锁保护数据,而协程不需要写变量保护,只需要判断状态就好了。 ## 进程、线程、协程的堆栈区别是什么? * 进程:有独立的堆栈,不共享堆也不共享栈;由操作系统调度; * 线程:有独立的栈,共享堆而不共享栈;由操作系统调度; * 协程:有独立的栈,共享堆而不共享栈;由程序员自己调度。 ## 进程间通信的意义是什么? 数据传输:一个进程需要将它的数据发送给另一个进程; 资源共享:多个进程间共享同样的资源; 通知事件:一个进程需要向另一个或一组进程发消息,通知它们发生了某种事件(如进程终止时要通知父进程)。 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。 ## 进程间高级通信机制如何分类? * 共享存储器系统(存储器中划分的共享存储区);实际操作中对应的是“剪贴板”(剪贴板实际上是系统维护管理的一块内存区域)的通信方式,比如举例如下:word进程按下ctrl+c,在ppt进程按下ctrl+v,即完成了word进程和ppt进程之间的通信,复制时将数据放入到剪贴板,粘贴时从剪贴板中取出数据,然后显示在ppt窗口上。 * 消息传递系统(进程间的数据交换以消息(message)为单位,当今最流行的微内核操作系统中,微内核与服务器之间的通信,无一例外地都采用了消息传递机制。应用举例:邮槽(MailSlot)是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。邮槽是一种单向通信机制,创建邮槽的服务器进程读取数据,打开邮槽的客户机进程写入数据。 * 管道通信系统(管道即:连接读写进程以实现他们之间通信的共享文件(pipe文件,类似先进先出的队列,由一个进程写,另一进程读))。实际操作中,管道分为:匿名管道、命名管道。匿名管道是一个未命名的、单向管道,通过父进程和一个子进程之间传输数据。匿名管道只能实现本地机器上两个进程之间的通信,而不能实现跨网络的通信。命名管道不仅可以在本机上实现两个进程间的通信,还可以跨网络实现两个进程间的通信。 * **管道**:管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的道端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样地,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。 * **信号量**:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其它进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段 * **消息队列**:是一个在系统内核中用来保存消 息的队列,它在系统内核中是以消息链表的形式出现的。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点 * **共享内存**:共享内存允许两个或多个进程访问同一个逻辑内存。**这一段内存可以被两个或两个以上的进程映射至自身的地址空间中**,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信\*\*。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。**共享内存是最快的IPC方式,它是针对其它进程间通信方式运行效率低而专门设计的。它往往与其它通信机制(如**信号量\*\*)配合使用,来实现进程间的同步和通信。 * **套接字**:套接字也是一种进程间通信机制,与其它通信机制不同的是,它可用于不同机器间的进程通信。 相关参考:[https://www.cnblogs.com/WindSun/p/11441090.html](https://www.cnblogs.com/WindSun/p/11441090.html) ## 进程的调度 **调度种类** * **高级调度**:(High-Level Scheduling)又称为作业调度,它决定把后备作业调入内存运行 * **低级调度**:(Low-Level Scheduling)又称为进程调度,它决定把就绪队列的某进程获得CPU * **中级调度**:(Intermediate-Level Scheduling)又称为在虚拟存储器中引入,在内、外存对换区进行进程对换 **非抢占式调度与抢占式调度** * **非抢占式**:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度进程调度某事件而阻塞时,才把处理机分配给另一个进程 * **抢占式**:操作系统将正在运行的进程强行暂停,由调度程序将CPU分配给其他就绪进程的调度方式 **调度算法** **FIFO或First Come, First Served (FCFS)先来先服务** * 调度的顺序就是任务到达就绪队列的顺序 * 公平、简单(FIFO队列)、非抢占、不适合交互式 * 未考虑任务特性,平均等待时间可以缩短 **Shortest Job First (SJF)** * 最短的作业(CPU区间长度最小)最先调度 * SJF可以保证最小的平均等待时间 **Shortest Remaining Job First (SRJF)** * SJF的可抢占版本,比SJF更有优势 * SJF(SRJF): 如何知道下一CPU区间大小?根据历史进行预测: 指数平均法 **优先权调度** * 每个任务关联一个优先权,调度优先权最高的任务 * 注意:优先权太低的任务一直就绪,得不到运行,出现“饥饿”现象 **Round-Robin(RR)轮转调度算法** * 设置一个时间片,按时间片来轮转调度(“轮叫”算法) * 优点: 定时有响应,等待时间较短;缺点: 上下文切换次数较多 * 时间片太大,响应时间太长;吞吐量变小,周转时间变长;当时间片过长时,退化为FCFS **多级队列调度** * 按照一定的规则建立多个进程队列 * 不同的队列有固定的优先级(高优先级有抢占权) * 不同的队列可以给不同的时间片和采用不同的调度方法 * 存在问题1:没法区分I/O bound和CPU bound * 存在问题2:也存在一定程度的“饥饿”现象 **多级反馈队列** * 在多级队列的基础上,任务可以在队列之间移动,更细致的区分任务 * 可以根据“享用”CPU时间多少来移动队列,阻止“饥饿” * 最通用的调度算法,多数OS都使用该方法或其变形,如UNIX、Windows等 ## 什么是共享内存,好处是什么? 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据\[1\]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。 ## 共享内存是怎么实现的? > 简单的说,共享内存是通过把同一块内存分别映射到不同的进程空间中实现进程间通信。 而共享内存本身不带任何互斥与同步机制。但当多个进程同时对同一内存进行读写操作时会破坏该内存的内容,所以,在实际中,同步与互斥机制需要用户来完成。 ## 共享内存的特点是什么? (1)共享内存就是允许两个不想关的进程访问同一个内存 (2)共享内存是两个正在运行的进程之间共享和传递数据的最有效的方式 (3)不同进程之间共享的内存通常安排为同一段物理内存 (4)共享内存不提供任何互斥和同步机制,一般用信号量对临界资源进行保护。 (5)接口简单 ## 一个程序从开始运行到结束的完整过程(四个过程)是什么? 预处理:条件编译,头文件包含,宏替换的处理,生成.i文件。 编译:将预处理后的文件转换成汇编语言,生成.s文件 汇编:汇编变为目标代码(机器代码)生成.o的文件 链接:连接目标代码,生成可执行程序