闲聊进程和线程

CPU

cpu是计算机的中央运算单元,从内存里面读取一条一条的代码指令,然后根据指令来执行运算(加,减,乘,除,复制数据等)。

CPU在运算的过程中一些数据存放在CPU的寄存器和内存里面。

CPU里面有各种寄存器,指令指针寄存器存放当前执行到那条代码指令(写完程序后被编译器编译成二进制指令代码)。

内核与虚拟内存

启动代码后运行OS内核,内核里也有线程,这个我们把它叫做内核态。内核启动以后,内核将物理内存管理起来,内核提供虚拟内存管理机制给每个进程内存服务。

每个进程都有自己的虚拟内存空间,这里的空间只是一个数字空间,没有划分实际的物理内存。多个进程内存都是独立的相互不影响,物理内存只有一个,多个进程不会因为直接使用物理内存而冲突。

物理内存管理

进程需要内存的时候,OS分配一块虚拟内存,然后OS在从自己管理的物理内存里面分配出来物理内存页,然后通过一个MMU的单元,将分配的虚拟内存与物理内存页映射起来。读写虚拟内存地址最终通过映射来使用物理内存地址,这样每个进程之间的内存是独立的,安全的。每个进程会把虚拟内存空间分成4个段(代码段, 数据端,堆,栈)。

  • 代码段:用来存放进程的代码指令。
  • 数据端:用来存放全局变量的内存。
  • 堆:调用os的malloc/free 来动态分配的内存。
  • 栈:用来存放局部变量,函数参数,函数调用与跳转。

进程与线程关系

每个进程相当于一个容器,所有代码里面需要的资源和机制都在进程里面。线程是OS独立调度执行的单元,OS调度执行的单位就是线程,线程需要以进程作为容器和使用进程相关的环境。

  • 每个线程共享进程的代码段内存空间,所以我们编写多线程代码的时候,可以在任何线程调用任何函数。
  • 每个线程共享进程的数据段内存空间,所以我们编写多线程代码的时候,可以在任何线程访问全局变量。
  • 每个线程共享进程的堆,所以我们编写多线程代码的时候,可以在一个线程访问另外一个线程new/malloc出来的内存对象。
  • 每个线程都有自己的栈的空间,所以可以独立调用执行函数(参数,局部变量,函数跳转)相互之间不受影响。

OS调度线程

CPU一般会有多个核心,每个核心都调度一个线程执行,最多同时可调度几个线程。

OS的功能就是要在合适的时候分配CPU核心来调度合适的线程。为了能实现多任务并发,OS不允许一个OS核心长期固定调度一个线程。

OS会根据线程的优先级分配每次调度最多执行的时间片,这个时间一到,无论如何都要重新调度一次线程(也许还是调度到这个线程)。

除了时间片以外,线程会等待某些条件(磁盘读取文件,网卡发送完数据,线程休眠, 等待用户操作)这样也会把这个线程挂起,OS会重新找一个新的线程继续执行,直到挂起的这个线程的条件满足了,重新把这个线程放到可调度队列里面,这个线程又有机会被OS调度CPU核心来执行。

每个线程“随时随地”都可能被OS中断执行,并调度到其它的线程执行。这样每个线程都会有一个运行时的环境(运行时CPU的每个寄存器的值、栈独立。栈的内存数据不会变。数据段、堆共用,可能调度回来会变)。

调度流程

当OS要把某个CPU核心调度出去给其它线程的时候,首先会把当前线程的运行环境(寄存器的值等)保存到内存,然后调度到其它线程,等再次调度回来的时候,再把原来保存到内存的寄存器的值,再设置会CPU核心的寄存器里面,这样就回到了调度出去之前的进度。

因为多线程之间共用了代码段(代码段只读,不会改),数据段(全局变量调度回来后,可能被其它线程篡改,不是调度之前的那个值了),堆(调度回来后,动态内存分配的对象内存数据可能被其它线程出篡改),调度回来后,栈上的数据是不变的,因为每个线程都有自己的栈空间。

线程调度的开销就是:保存上下文执行环境,内核态运行算法决定接下来调度那个线程,切换这个线程的上下文环境。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值