深入拆解 Tomcat & Jetty
李号双
eBay 技术主管
38890 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
深入拆解 Tomcat & Jetty
15
15
1.0x
00:00/00:00
登录|注册

22 | 热点问题答疑(2):内核如何阻塞与唤醒进程?

共享资源
轻量级进程
用户空间和内核空间
虚拟内存和物理内存
task_struct数据结构
程序加载到内存
唤醒实现
阻塞实现
运行队列和等待队列
CPU调度
线程
进程
小结
阻塞与唤醒
进程和线程
内核如何阻塞与唤醒进程
文章

该思维导图由 AI 生成,仅供参考

在专栏的第三个模块,我们学习了 Tomcat 连接器组件的设计,其中最重要的是各种 I/O 模型及其实现。而 I/O 模型跟操作系统密切相关,要彻底理解这些原理,我们首先需要弄清楚什么是进程和线程,什么是虚拟内存和物理内存,什么是用户空间和内核空间,线程的阻塞到底意味着什么,内核又是如何唤醒用户线程的等等这些问题。可以说掌握这些底层的知识,对于你学习 Tomcat 和 Jetty 的原理,乃至其他各种后端架构都至关重要,这些知识可以说是后端开发的“基石”。
在专栏的留言中我也发现很多同学反馈对这些底层的概念很模糊,那今天作为模块的答疑篇,我就来跟你聊聊这些问题。

进程和线程

我们先从 Linux 的进程谈起,操作系统要运行一个可执行程序,首先要将程序文件加载到内存,然后 CPU 去读取和执行程序指令,而一个进程就是“一次程序的运行过程”,内核会给每一个进程创建一个名为task_struct的数据结构,而内核也是一段程序,系统启动时就被加载到内存中了。
进程在运行过程中要访问内存,而物理内存是有限的,比如 16GB,那怎么把有限的内存分给不同的进程使用呢?跟 CPU 的分时共享一样,内存也是共享的,Linux 给每个进程虚拟出一块很大的地址空间,比如 32 位机器上进程的虚拟内存地址空间是 4GB,从 0x00000000 到 0xFFFFFFFF。但这 4GB 并不是真实的物理内存,而是进程访问到了某个虚拟地址,如果这个地址还没有对应的物理内存页,就会产生缺页中断,分配物理内存,MMU(内存管理单元)会将虚拟地址与物理内存页的映射关系保存在页表中,再次访问这个虚拟地址,就能找到相应的物理内存页。每个进程的这 4GB 虚拟地址空间分布如下图所示:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了操作系统内核如何阻塞与唤醒进程的机制,以及进程和线程的概念。首先介绍了进程和线程在Linux系统中的运行原理,包括虚拟内存和物理内存的关系,用户空间和内核空间的划分,以及系统调用的作用。接着详细解释了阻塞与唤醒的过程,包括进程状态的转换和CPU调度的机制。最后通过一次Socket read系统调用的过程,生动展示了CPU在用户态和内核态之间的切换,以及数据在内核空间和用户空间之间的传递。本文内容深入浅出,适合后端开发人员了解操作系统底层原理,对于理解Tomcat和Jetty等后端架构的工作原理具有重要意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Tomcat & Jetty 》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(44)

  • 最新
  • 精选
  • 帽子丨影
    老师好,既然用户态运行时也会占用cpu,内核态又可以访问整个虚拟空间,为什么不让cpu一直处在内核态呢,这样就没有切换带来损耗了

    作者回复: 如果是这样的话,你写的应用程序直接在内核态运行,权限级别太高,出了问题会导致整个操作系统崩溃,所有才有了用户态核心态,算是一种隔离和容错吧。

    2019-09-24
    39
  • 一塌糊涂
    老师问个问题,用户态切换到内核态,使用的是虚拟空间内核地址?这时用户线程会挂起执行内核线程吗?这是两个线程吗?

    作者回复: cpu处于内核态时使用的是内核地址空间,用户线程的挂起其实是由内核完成的,具体来说就是系统调用发触发软中断,cpu在内核态模式下执行软中断程序,也就是系统调用的具体实现函数(内核代码),内核代码执行过程中发现网络数据未就绪就主动让出cpu。这个时候才会将当前线程阻塞,因此从这个角度看,不是两个线程,而是一个线程在不同cpu模式下的执行过程。

    2019-07-11
    3
    31
  • Liam
    如果是通过mmap读数据,流程是怎样的呢? 1 如果没有数据,是否会阻塞? 2 不需要拷贝数据?意思是用户进程可以直接读mmap,不需要拷贝到堆吗?

    作者回复: mmap不支持Socket读写,只支持磁盘文件。 通过mmap将文件映射到内存后,直接写读写内存,内核会负责将数据刷新到磁盘文件。

    2019-06-29
    15
  • 佑儿
    虚拟内存是一个联系的地址空间,该地址空间由不一定连续的物理内存组成。 这样理解对吗?

    作者回复: 对的

    2019-07-01
    14
  • nightmare
    老师今天讲了线程和进程,进程和线程都是统一在内核空间建立task_truct,根据代码是否有系统调用在用户态和内核态来做上下文切换,然后还讲了read的系统调用过程以及进程的虚拟内存和物理内存的机制,有一点没明白,是每个进程都会有一个虚拟内核空间吗?然后进程的虚拟内核空间映射到系统管理的内核空间上?

    作者回复: 每一个进程的进程空间都包含内核空间,但是内核是各进程共享的,因此可以这里理解,内核代码运行过程中访问的内存空间被映射到各个进程空间的高地址3-4G。

    2019-06-30
    11
  • 长脖子树
    看了作者的文章又去看了 copy-on-write 和 MappedByteBuffer 了解又加深了一层 哈哈

    作者回复: 赞

    2019-08-16
    9
  • 妥协
    之前有讲到过,jvm用到的内存空间,在本文中介绍的进程的地址空间划分中,是属于那一部分?

    作者回复: 这样理解,JVM启动时在用户空间上分配了一大块连续内存空间作为JVM内存区域,具体在进程空间的数据区和栈区的中间。

    2019-07-01
    9
  • 飞翔
    用户态和用户空间是啥关系?

    作者回复: 你可以理解为CPU上有个开关,可以设置CPU的工作模式:用户态和内核态。在用户态模式下访问用户空间,也就是低地址的3GB。

    2019-06-29
    2
    8
  • brianway
    “线程有自己的task_struct结构体和运行栈区,但是线程的其他资源都是跟父进程共用”,这句话怎么理解。线程的task_struct结构体和运行栈区在图中哪个部分? 是从进程的内核空间里面分配出来的,还是用户空间里分配出来的?具体哪个部分的内存?

    作者回复: 每个线程都有tast_struct,由内核创建,在内核空间上。

    2019-07-05
    6
  • 迎风劲草
    老师,task_struct 具体是什么结构,都存储了什么?

    作者回复: task_struct存储了一个进程的所有信息,比如进程id,执行了什么程序,工作目录,打开了什么文件...

    2019-07-01
    6
收起评论
显示
设置
留言
44
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部