• home > theory > CST > Constitution >

    同步与异步:并发/并行/进程/线程/多cpu/多核/超线程/管程

    Author:zhoulujun Date:

    多核、多处理器(多CPU)、多线程多核:几核就是真的有几个物理核心。CPU的性能主要靠提高核心工作频率来提高,由于物理限制,不能把频率无


    多核、多处理器(多CPU)、多线程

    • 多核:几核就是真的有几个物理核心。CPU的性能主要靠提高核心工作频率来提高,由于物理限制,不能把频率无限提高,所以发展出多核心的CPU。即一枚处理器上集成多个计算引擎(内核),共享缓存、内存、寄存器。A8处理器是一款双核处理器。

    • 多处理器:包含多个CPU,CPU之间共享内存、I/O设备、控制器、外部设备,整个硬件系统由统一的操作系统控制,在处理器和程序之间实现作业、任务、程序、数组及其元素各级的全面并行。目前主流的服务器架构,超级计算机,都是多CPU多核架构。

    • 多线程:线程就是我们为了让一个进程能够同时干多件事情而发明的“分身术”,拥有最小系统资源,共享进程资源的基本调度单位。核是物理的,线程是虚拟的,双核4线程,看起来很像4核,但比真实的4核4线程慢,却比双核双线程快。

    CPU并行技术主要是应用于大型的计算任务,原理就是将各个部分分配到各cpu的不同线程中同时处理 ,加快总进度。但是对于个人普通的运算来说没啥用甚至是1+1<2,并行不仅需要cpu的交火,也需要软件的强大支持

    本世纪初,热衷于攒机,当时就用过双CPU主板,微星694D,双CPU最大的特点就是浏览器打开一个新窗口秒开。而其他单CPU机器都要折腾个3秒钟才打开一个新浏览器窗口。个人之前做影视后期的,都是用超微(SUPERMICRO)的主板。现阶段的消费级平台的瓶颈根本不在cpu性能上,属于完全没有必要的技术。

    超威双路CPU主板超微4路CPU主板

    多核cpu和多cpu

    多个物理CPU,CPU通过总线进行通信,效率比较低。

    1775767-20190905203811357-1141233368.png

    多核CPU,不同的核通过L2 cache进行通信,存储和外设通过总线与CPU通信

    1775767-20190905203817952-1381061451.png

    CPU的缓存

    CPU缓存是位于CPU与内存之间的临时数据交换器,它的容量比内存小的多但是交换速度却比内存要快得多。CPU缓存一般直接跟CPU芯片集成或位于主板总线互连的独立芯片上。

    随着多核CPU的发展,CPU缓存通常分成了三个级别:L1,L2,L3。级别越小越接近CPU,所以速度也更快,同时也代表着容量越小。L1 是最接近CPU的, 它容量最小(例如:32K),速度最快,每个核上都有一个 L1 缓存,L1 缓存每个核上其实有两个 L1 缓存, 一个用于存数据的 L1d Cache(Data Cache),一个用于存指令的 L1i Cache(Instruction Cache)。L2 缓存 更大一些(例如:256K),速度要慢一些, 一般情况下每个核上都有一个独立的L2 缓存; L3 缓存是三级缓存中最大的一级(例如3MB),同时也是最慢的一级, 在同一个CPU插槽之间的核共享一个 L3 缓存。

    读取数据过程。就像数据库缓存一样,首先在最快的缓存中找数据,如果缓存没有命中(Cache miss) 则往下一级找, 直到三级缓存都找不到时,向内存要数据。一次次地未命中,代表取数据消耗的时间越长。

    计算过程。程序以及数据被加载到主内存;指令和数据被加载到CPU的高速缓;CPU执行指令,把结果写到高速缓存;高速缓存中的数据写回主内存

    并发和并行

    • 并发(concurrent [kənˈkɜːrənt] ):当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。这种方式我们称之为并发。

      CPU根据一定的线程调度算法,频繁的进行线程切换,当正在执行的一个线程需要进行IO操作或者需要访问内存的时候,CPU完全可以放弃该线程,转而调度线程就绪队列上的其他线程,被放弃的线程则进入阻塞状态,IO操作或者访问内存操作结束之后,该线程可以进入线程就绪队列上。

    • 并行(Parallel [ˈpærəlel]):当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行。

      多核CPU可以同时执行多个进程,进程数与CPU核数相当。但宏观上说,由于CPU会分时间片执行多个进程,所以实际执行进程个数会远多于CPU核数。

    并发架构思维导图

    同一个进程下的所有线程都只能在CPU同一个核下运行,同一进程下的多个线程在同一个核下轮流使用处理器,因为处理速度快,看起来是并行,实际上同一进程下的多线程是串行。

    并发和并行区别

    • 并发是指两个或多个事件在同一时间间隔内发生

    • 并行是指两个或者多个事件在同一时刻发生

    在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行

    在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。

    倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。


    线程与进程

    在单道程序下,作业是一个接着一个进行;

    在多道程序环境下,允许多个程序并发执行,程序在一个CPU上通过周期性切换达到同步执行的效果。但是,此时它们将失去封闭性,并具有间断性及不可再现性的特征。

    为此引入了进程(Process)的概念,以便更好地描述和控制程序的并发执行,实现操作系统的并发性和共享性。

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

    因为 CPU 执行速度很快,进程间的换进换出也非常迅速,因此我们很难对多个并行进程进行跟踪,所以,在经过多年的努力后,操作系统的设计者开发了用于描述并行的一种概念模型:顺序进程(sequential processes),简称为 进程(process) 

    一个进程就是一个正在执行的程序的实例,进程也包括程序计数器、寄存器和变量的当前值。从概念上来说,每个进程都有各自的虚拟 CPU,但是实际情况是 CPU 会在各个进程之间进行来回切换。



    进程(Process)

    进程就是进行中的程序(一组指令的有序集合),当一个程序被加载到内存中之后就变成了进程(进程=程序+执行)。进程有独立的地址空间,在保护模式下自己出了问题不会对其他进程产生影响。进程是操作系统分配资源的基本单位。 

    进程和线程都是一个时间段的描述,是CPU工作时间段的描述。

    一个最最基础的事实:CPU太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM和别的挂在各总线上的设备完全是望其项背。那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话就是在CPU看来就是轮流着来。

    一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,等待下一次CPU的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被CPU临幸的运行环境,必须保存。

    串联起来的事实:前面讲过在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文。。。。

    进程和线程就是这样的背景出来的,两个名词不过是对应的CPU时间段的描述,名词就是这样的功能。

    进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文


    进程的三种状态:

    • 阻塞态:又称等待状态,等待某个事件完成的过程。因为等待某一事件而暂停运行,所以阻塞。如等待某资源为可用(不包括处理机)或等待输入/输出完成。即使处理机空闲,该进程也不能运行。

    • 就绪态:等待系统分配CPU以便运行,进程已处于准备运行的状态,即进程获得了除处理机之外的一切所需资源,一旦得到处理机即可运行。

    • 执行态:占有CPU正在运行。进程正在处理机上运行。在单处理机(一个CPU)环境下,每一时刻最多只有一个进程处于运行状态。

     进程的三种状态切换图示1323506-0d9425f8b9dd4661.jpg


    进程通信

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

    • 通过消息Queue: 消息队列是内容为消息的链表

    • 通过管道Pipe:管道是一种半双工的通信方式,数据只能单向流动

    • 通过共享内存:也就是所有进程可以在一段共有的内存上访问数据。

    1323506-131f74bddafee46e.jpg


    线程(Thread)

    线程允许在同一个进程中存在多个程序控制流。线程可以共享进程的资源,但是每个线程都有自己的程序计数器、栈和局部变量表。同一进程中的不同线程能够访问相同的变量,并且在同一个堆上分配对象。

    1.png

    引入进程的目的,是为了使多道程序并发执行,以提高资源利用率和系统吞吐量;

    引入线程,则是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

    线程最直接的理解就是“轻量级进程”,它是一个基本的CPU执行单元,也是程序执行流的最小单元,由线程ID、程序计数器、寄存器集合和堆栈组成。

    线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。

    引入线程后,进程的内涵发生了改变,进程只作为除CPU以外系统资源的分配单元,线程则作为处理机的分配单元

    线程是处理机的独立调度单位,多个线程是可以并发执行的。在单CPU的计算机系统中,各线程可交替地占用CPU;在多CPU的计算机系统中,各线程可同时占用不同的CPU,若各个CPU同时为一个进程内的各线程服务则可缩短进程的处理时间。



    进程与线程区别

    • 进程是cpu资源分配的最小单位,线程是cpu调度的最小单位

    • 一个程序至少有一个进程,一个进程至少有一个线程。线程依赖于进程才能运行

    • 线程本身拥有很少资源(线程标识符、程序计数器、一组寄存器的值、堆栈),与同属进程的其他线程共享进程拥有的资源(代码段、数据段、打开的文件、I/O设备等)。

    • 线程开销小,但一个线程死掉等于整个进程死掉,不利于资源管理和保护。而进程正好相反,开销大,但相对线程安全。

    • 进程间通信(IPC)需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以直接读/写进程数据段(如全局变量)来进行通信。

    人们通常意义上的多线程指的是,由于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工作时间段的描述,不过是颗粒大小不同

    • 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 

    • 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 

    一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。

    每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 

    从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

    多线程中堆和栈区

    进程在执行过程中拥有独立的内存单元,而该进程的多个线程共享内存,从而极大地提高了程序的运行效率。 

    线程在进程的内存空间中有自己的内存空间用来临时保存自己的堆栈或寄存器内容或程序计数器,用来恢复继续运行,进程中不同的线程不像不同的进程之间存在着很大的独立性,所有线程都有完全一样的地址空间,这意味着线程之间共享全局变量。由于各个线程都可以访问进程地址空间中的任意内存地址,所以一个线程可以修改读取甚至删除另一线程的堆栈,线程之间是没有保护的。因为不同的线程肯定来自同一进程也就是同一用户,他们之间不会有敌意,他们之间还可以共享打开的文件集、子进程、以及相关信号。而不同的线程之间的通信就复杂的多,同一进程中的多个线程是相互信任的,而不同的进程之间是不信任的。

    很多现代操作系统中,一个进程的(虚)地址空间大小为4G,分为系统空间和用户空间两部分,系统空间为所有进程共享,而用户空间是独立的,一般WINDOWS进程的用户空间为2G

     一个进程中的所有线程共享该进程的地址空间,但它们有各自独立的(私有的)栈(stack),Windows线程的缺省堆栈大小为1M。堆(heap)的分配与栈有所不同,一般是一个进程有一个C运行时堆,这个堆为本进程中所有线程共享,Windows进程还有所谓进程默认堆,用户也可以创建自己的堆。

    • 堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

    • 栈是个线程独有的,保存其运行状态和局部自动变量的栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe的。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

    进程空间地址存储的内容线程空间地址中存在的内容
    地址空间程序计数器
    全局变量寄存器
    打开的文件集堆栈
    子进程状态
    账户信息
    优先级
    信号

    那么什么时候该使用线程?

    因为我们知道线程是在进程中的运行时不断交替运行的单位,当某一线程遇到io阻塞,这个时候让当前线程等待总线上的数据,保存当前线程的现场(堆栈和寄存器),运行另一线程。所以当某项工作大多时进行的都是cpu运算,那么多线程显然毫无意义,而且还会增加线程之间切换保存线程的额外工作,所以cpu密集型的工作不适合用线程。但是当工作中有运算和iO处理工作时,显然将这些工作分配给多线程是可以不浪费cpu宝贵的运算时间,让cpu忙起来提高工作效率的好办法。

    进程和线程在多核cpu,多cpu中的运行关系

    操作系统会拆分CPU为一段段时间的运行片,轮流分配给不同的程序。

    • 对于多cpu,多个进程可以并行在多个cpu中计算,当然也会存在进程切换;

    • 对于单cpu,多个进程在这个单cpu中是并发运行,根据时间片读取上下文+执行程序+保存上下文。

    同一个进程同一时间段只能在一个cpu中运行,如果进程数小于cpu数,那么未使用的cpu将会空闲

    • 对于多核cpu,进程中的多线程并行执行。

    • 对于单核cpu,多线程在单cpu中并发执行,根据时间片切换线程。

    同一个线程同一时间段只能在一个cpu内核中运行,如果线程数小于cpu内核数,那么将有多余的内核空闲

    多线程的概念主要有两种:一种是用户态多线程;一种是内核态多线程,对于内核态多线程(java1.2之后用内核级线程),在操作系统内核的支持下可以在多核下并行运行;

    线程的实现方式

    线程的实现可以分为两类:用户级线程(User-LevelThread, ULT)和内核级线程(Kemel-LevelThread, KLT)。内核级线程又称为内核支持的线程。

    用户级线程中

    在用户级线程(User Thread中,有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在。应用程序可以通过使用线程库设计成多线程程序。通常,应用程序从单线程起始,在该线程中开始运行,在其运行的任何时刻,可以通过调用线程库中的派生例程创建一个在相同进程中运行的新线程。

    用户线程是在用户空间实现的,对线程的创建、撤销、通信、同步等功能的实现,无需内核的支持,因而内核完全不知道用户级线程的存在;此时进程和用户线程是一对多的关系。

    线程切换不需要转到内核空间。对一个进程而言,其所有的线程管理数据结构均在该进程自己的用户空间,管理线程切换的线程库也在用户地址空间运行,从而不需要切换到内核方式来管理线程,从而节省了内核态和用户态之间切换的开销

    又因为对线程的创建、撤销、通信、同步等功能的实现不需要内核来完成,都需要用户程序自己来处理,用户程序一般都比较复杂,所以,用这种方式来处理创建多线程的程序越来越少。

    用户级线程结构



    内核级线程中

    在内核级线程中(KLT,Kernel-Level Thread),线程管理的所有工作由内核(Kernel)完成,应用程序没有进行线程管理的代码,只有一个到内核级线程的编程接口。内核为进程及其内部的每个线程维护上下文信息,调度也是在内核基于线程架构的基础上完成。

    由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上。每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核叫做多线程内核。

    程序一般不会去直接使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(LWP),即通常意义上的线程。由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。轻量级进程与内核线程之间 1:1 关系称为一对一的线程模型。

    在一些系统中,使用组合方式的多线程实现。线程创建完全在用户空间中完成,线程的调度和同步也在应用程序中进行。一个应用程序中的多个用户级线程被映射到一些(小于或等于用户级线程的数目)内核级线程上。上图(c)说明了用户级与内核级的组合实现方式。


    内核线程调度

    程序与进程

    1. 进程是程序及其数据在计算机上的一次运行活动,是一个动态的概念。而程序是一组有序的指令集合,是一种静态的概念。

    2. 进程是程序的一次执行过程,它是动态地创建和消亡的,具有一定的生命周期,是暂时存在的;而程序则是一组代码的集合,它是永久存在的,可长期保存。

    3. 一个进程可以执行一个或几个程序,一个程序也可以构成多个进程。进程可创建进程,而程序不可能形成新的程序。

    4. 进程与程序的组成不同。进程的组成包括程序、数据和PCB。进程的运行实体是程序,离开程序的进程没有存在的意义。

    作业与进程

    进程是系统资源的使用者,系统的资源大部分都是以进程为单位分配的。

    而用户使用计算机是为了实现一串相关的任务,通常把用户要求计算机完成的这一串任务称为作业。

    进程是作业的执行(计算机完成任务)的表现。

    线程的思维导图


    协程

    人们发现 像 Web Server 这种东西, 完全是靠IO嘛, Thread Per Message 完全可以一波流, 但创建和销毁 Thread 成本依旧很高, 于是协程这种东西也就又开始流行了

    v2-0286f1c2a82b32a8aad5bf42fb04f1f2_720w.jpg


    管程的定义

    系统中的各种硬件资源和软件资源,均可用数据结构抽象地描述其资源特性,即用少量信息和对资源所执行的操作来表征该资源,而忽略了它们的内部结构和实现细节。

    管程是由一组数据以及定义在这组数据之上的对这组数据的操作组成的软件模块,这组操作能初始化并改变管程中的数据和同步进程。

    管程的组成

    1) 局部于管程的共享结构数据说明。

    2) 对该数据结构进行操作的一组过程。

    3) 对局部于管程的共享数据设置初始值的语句。

    管程的基本特性

    1) 局部于管程的数据只能被局部于管程内的过程所访问。

    2) 一个进程只有通过调用管程内的过程才能进入管程访问共享数据。

    3) 每次仅允许一个进程在管程内执行某个内部过程。

    由于管程是一个语言成分,所以管程的互斥访问完全由编译程序在编译时自动添加,无需程序员关注,而且保证正确。


    同步与互斥

    在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步的概念。

    临界资源

    虽然多个进程可以共享系统中的各种资源,但其中许多资源一次只能为一个进程所使用,我们把一次仅允许一个进程使用的资源称为临界资源

    许多物理设备都属于临界资源,如打印机等。此外,还有许多变量、数据等都可以被若干进程共享,也属于临界资源。

    对临界资源的访问,必须互斥地进行,在每个进程中,访问临界资源的那段代码称为临界区

    为了保证临界资源的正确使用,可以把临界资源的访问过程分成四个部分:

    1. 进入区。为了进入临界区使用临界资源,在进入区要检查可否进入临界区,如果可以进入临界区,则应设置正在访问临界区的标志,以阻止其他进程同时进入临界区。

    2. 临界区。进程中访问临界资源的那段代码,又称临界段。

    3. 退出区。将正在访问临界区的标志清除。

    4. 剩余区。代码中的其余部分。

    do {
        entry section;  
        critical section;  //临界区
        exit section;  //退出区
        remainder section;  //剩余区
    }while (true)

    并发进程的执行会产生相互制约的关系:

    1、一种是进程之间竞争使用临界资源,只能让它们逐个使用,这种现象称为互斥,是一种竞争关系;

    2、另一种是进程之间协同完成任务,在关键点上等待另一个进程发来的消息,以便协同一致,是一种协作关系。

    同步

    同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系

    进程间的直接制约关系就是源于它们之间的相互合作

    例如,输入进程A通过单缓冲向进程B提供数据。当该缓冲区空时,进程B不能获得所需数据而阻塞,一旦进程A将数据送入缓冲区,进程B被唤醒。反之,当缓冲区满时,进程A被阻塞,仅当进程B取走缓冲数据时,才唤醒进程A。

    互斥

    互斥亦称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待, 当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源

    例如,在仅有一台打印机的系统中,有两个进程A和进程B,如果进程A需要打印时, 系统已将打印机分配给进程B,则进程A必须阻塞。一旦进程B将打印机释放,系统便将进程A唤醒,并将其由阻塞状态变为就绪状态。

    为禁止两个进程同时进入临界区,同步机制应遵循以下准则:

    1、空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。

    2、忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待。

    3、有限等待。对请求访问的进程,应保证能在有限时间内进入临界区。

    4、让权等待。当进程不能进入临界区时,应立即释放处理器,防止进程忙等待。


    异步IO

    什么是异步IO呢?

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

    那么因为CPU和IO的速度有天壤之别,所以如果一个任务在执行的过程中大部分时间都在等待IO操作,最好引入多进程模型或者多线程模型来支持多任务并发执行。

    为多个用户服务,每个用户都会分配一个线程,如果遇到IO导致线程被挂起,其他用户的线程不受影响。

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

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

     异步IO与事件驱动

    CPU 密集型程序创建多少个线程合适?

    CPU密集型,线程数量 = CPU 核数(逻辑)就可以了,但是实际上,数量一般会设置为 CPU 核数(逻辑)+ 1, 为什么呢?

    《Java并发编程实战》这么说:

    计算(CPU)密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个“额外”的线程,可以确保在这种情况下CPU周期不会中断工作。

    所以对于CPU密集型程序, CPU 核数(逻辑)+ 1 个线程数是比较好的经验值的原因了

    I/O密集型程序创建多少个线程合适?

    上面已经让大家按照图多画几个周期(你可以动手将I/O耗时与CPU耗时比例调大,比如6倍或7倍),这样你就会得到一个结论,对于 I/O 密集型程序:最佳线程数 = (1/CPU利用率) = 1 + (I/O耗时/CPU耗时)

    这是一个CPU核心的最佳线程数,如果多个核心,那么 I/O 密集型程序的最佳线程数就是:

    最佳线程数 = CPU核心数 * (1/CPU利用率) = CPU核心数 * (1 + (I/O耗时/CPU耗时))



    参考内容:

    计算机操作系统原理总结 https://www.jianshu.com/p/92a13d2918f4

    多线程:原理分析整理  https://juejin.im/post/5c14bf1af265da613f2f5e90

    操作系统原理(二),进程、线程 https://www.jianshu.com/p/d89d650e4114

    面试问我,创建多少个线程合适?我该怎么说 https://www.jianshu.com/p/f30ee2346f9f

    进程,线程与多核,多cpu之间的关系 https://www.cnblogs.com/valjeanshaw/p/11469514.html

    https://www.zhihu.com/question/25532384/answer/1157991430

    https://www.zhihu.com/question/271821176/answer/364029483


    转载本站文章《同步与异步:并发/并行/进程/线程/多cpu/多核/超线程/管程》,
    请注明出处:https://www.zhoulujun.cn/html/theory/ComputerScienceTechnology/Constitution/2020_0619_8474.html