进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。–维基百科
1,进程:
操作系统资源分配的最小单元。
程序的实例。程序只是硬盘中堆切的数据和代码也即是文本。
虚拟内存就是进程的抽象一部分。
2,线程:
多数教科书的定义:线程是CPU调度的基本单位。
是进程上下文中(计算机运行程序时的环境)一条单一顺序的控制流。
谈到cpu调度,那就会设及到时间片调度,cpu只关注时间片分配。
既然是切换那就有两种调度方式:
1,基于进程的cpu调度
2,基于线程的cpu调度
对于现在的多核来说,一个进程中可能包含多种任务在运行,比如浏览器进程,如果切换的话会多保存n个任务的计算机运行行现场,导致开销极大。如果一个任务完成了,需要等其他任务完成后再切换,则至少会有某个核闲置,导致资源浪费。
基于线程的调度的话,只需要切换当前任务的PC和一些寄存器状态,栈等运行现场。只要你任务完成或者时间片用完,我就切换掉你,换一个线程过来。至于这个换过来的线程是同一个进程的线程还是其他进程的线程我不管,因为我是以线程为调度单位的。显然,第二种方式能够充分利用好CPU的所有核,不至于让某些核无所事事。
用户级线程:
内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu。
在用户空间模拟操作系统对进程的调度,来调用一个进程中的线程,每个进程中都会有一个运行时系统,用来调度线程。此时当该进程获取cpu时,进程内再调度出一个线程去执行,同一时刻只有一个线程执行。
在这在模型下,程序员需要自己实现线程的数据结构、创建销毁和调度维护。也就相当于需要实现一个自己的线程调度内核,而同时这些线程运行在操作系统的一个进程内,最后操作系统直接对进程进行调度,即操作系统只认为该进程是一个单线程进程。
这样做有一些优点,首先就是确实在操作系统中实现了真实的多线程,其次就是线程的调度只是在用户态,减少了操作系统从内核态到用户态的切换开销。
当然缺点也很明显:
这种模式最致命的缺点也是由于操作系统不知道线程的存在,因此当一个进程中的某一个线程进行系统调用时,比如缺页中断而导致线程阻塞,此时操作系统会阻塞整个进程,即使这个进程中其它线程还在工作。还有一个问题是假如进程中一个线程长时间不释放CPU,因为用户空间并没有时钟中断机制,会导致此进程中的其它线程得不到CPU而持续等待。
python协程是用户态线程。
内核级线程:
特点:
当某个线程希望创建一个新线程或撤销一个已有线程时,它进行一个系统调用,这个系统调用通过对线程的更新完成线程创建或撤销工作
优点:
1、所有能够阻塞线程的调用都以系统调用的形式实现
2、如果某个线程引起了页面故障,内核可以很方便地检查该进程是否有任何其他可运行的线程
线程池的疑问?
如果不给任务流,线程池内的线程如何创建?
不理解点:
1,关于main函数里新建线程的理解摘抄:
main函数,是进程这个容器中创建的第一个线程,所以它是主线程。
X_thread() 这个函数对于CPU而言根本没觉察到它是一个函数。
唯一的不同就是, 进入到函数的时候, 有一堆的汇编指令在那里保存当前的寄存器、堆栈和上下文。
这些asm,都是编译的时候生成的。
2,
抛开各种技术细节,从应用程序角度讲:
1、在单核计算机里,有一个资源是无法被多个程序并行使用的:cpu。
没有操作系统的情况下,一个程序一直独占着全都cpu。
如果要有两个任务来共享同一个CPU,程序员就需要仔细地为程序安排好运行计划--某时刻cpu和由程序A来独享,下一时刻cpu由程序B来独享
而这种安排计划后来成为OS的核心组件,被单独名命为“scheduler”,即“调度器”,它关心的只是怎样把单个cpu的运行拆分成一段一段的“运行片”,轮流分给不同的程序去使用,而在宏观上,因为分配切换的速度极快,就制造出多程序并行在一个cpu上的假象。
2、在单核计算机里,有一个资源可以被多个程序共用,然而会引出麻烦:内存。
在一个只有调度器,没有内存管理组件的操作系统上,程序员需要手工为每个程序安排运行的空间 -- 程序A使用物理地址0x00-0xff,程序B使用物理地址0x100-0x1ff,等等。
然而这样做有个很大的问题:每个程序都要协调商量好怎样使用同一个内存上的不同空间,软件系统和硬件系统千差万别,使这种定制的方案没有可行性。
为了解决这个麻烦,计算机系统引入了“虚拟地址”的概念,从三方面入手来做:
2.1、硬件上,CPU增加了一个专门的模块叫MMU,负责转换虚拟地址和物理地址。
2.2、操作系统上,操作系统增加了另一个核心组件:memory management,即内存管理模块,它管理物理内存、虚拟内存相关的一系列事务。
2.3、应用程序上,发明了一个叫做【进程】的模型,(注意)每个进程都用【完全一样的】虚拟地址空间,然而经由操作系统和硬件MMU协作,映射到不同的物理地址空间上。不同的【进程】,都有各自独立的物理内存空间,不用一些特殊手段,是无法访问别的进程的物理内存的。
PS:在有的操作系统里,进程不是调度单位(即不能被调度器使用),线程是最基本的调度单位,调度器只调度线程,不调度进程