做多线程应用开发,对于线程的理解是非常重要的,我们要为我们创建的每一个线程负责。这篇文章主要聊聊操作系统线程相关的主题,在了解线程定义、用户态与内核态、模态切换、线程上下文切换的基础之上再对常见的三种线程模型进行进一步介绍,希望对大家能够有所帮助。
线程定义我们在 github 上面给开源项目提交代码的时候,按照 comment 格式都要写 Motivation 这部分,我们今天讨论线程这个存在,也要讨论线程为什么存在。
在很多应用中需要同时执行多个任务,这些任务大部分甚至全部都可以相互独立的并行的执行。比如一个网络代理,传统的实现是用一个进程作为监听器来监听网络端口,当有客户端连接进来的时候,当前进程将会fork一个新的进程来处理客户端的请求。这种体系结构不好的地方如下:
线程的出现就是为了解决这些问题,线程之间拥有共享的进程空间用于共享数据、也有自己独立的运行空间类似一个轻量级的进程。
用户空间与内核空间在理解用户线程与内核线程之前、我们有必要了解一下用户空间与内核空间。现代操作系统的地址空间主要基于虚拟地址空间机制设计,和实际物理内存大小没关系,比如对于32位操作系统,它的寻址空间为2的32次方也就是4G,这里的寻址空间被称为虚拟存储空间。操作系统的核心是内核,独立于普通应用程序,具有最高权限,可以访问底层硬件设备以及受保护的空间,因此这部分包括驱动程序和操作系统。操作系统的设计者为了保证内核的安全,将用户进程设计为只有一定权限的程序,它不能够操作内核以及硬件。操作系统将虚拟存储空间划分为两部分,一部分是内核空间,一部分是用户空间。针对Linux操作系统而言,最高的1G字节供内核使用,称为内核空间,较低的3G字节供给各个进程使用,被称为用户空间。进程可以通过系统调用进入内核,Linux内核由所有进程共享。每个进程都拥有所有的虚拟地址空间,当进程运行用户代码的时候是运行在用户地址空间的,这时候 CPU 运行所需要的指令和数据都保存在用户空间,进程可以认为是指令+数据+CPU,因此这个时候我们把这个状态的进程叫做用户进程。当用户执行系统调用而陷入内核代码中执行的时候,当前进程运行的指令和数据都在内核空间,因此我们把这个状态的进程叫内核进程。用户进程和内核进程不是独立的两个进程的意思,而是进程运行的不同状态。值得注意的是,用户进程不能访问内核虚拟地址空间,内核进程可以访问全部的虚拟地址空间,因此用户进程和内核进程进行数据交换只能通过内核进程从用户地址空间取数据,然后放入用户地址空间。
系统调用涉及到进程从用户态到内核态的切换(mode switch),这个时候涉及到的切换主要是寄存器上下文的切换,和通常所说的进程上下文切换不同,mode switch的消耗相对要小很多。
用户线程与内核线程上面可以看出,用户线程与内核线程的区别主要在于指令与数据运行于不同虚拟地址空间,用户线程和内核线程也可以叫做用户空间线程和内核空间线程。用户线程由用户代码支持,内核线程由操作系统内核支持。欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |