用户级线程
一、概述
用户级线程的实现就是把整个线程实现部分放在用户空间中,内核对线程一无所知,内核看到的就是一个单线程进程。
对于线程的底层实现,现在很少有操作系统会使用单纯的用户级线程这中线程模型来实现。
注:对于实现的是用户级线程的操作系统而言,CPU 调度的基本单位看起来像是进程(因为在内核看来,这些进程都是单线程的,所以对单线程的调度就像是在调度进程一样)。
二、优点
- 整个用户级线程的切换发生在用户空间,这样的线程切换至少比陷入内核要快一个数量级(不需要陷入内核、不需要上下文切换、不需要对内存高速缓存进行刷新,这就使得线程调度非常快捷)
- 用户级线程有比较好的可扩展性,线程能够利用的表空间和堆栈空间比内核级线程多,这是因为在内核空间中内核线程需要一些固定的表格空间和堆栈空间,如果内核线程的数量非常大,就会出现问题,因为内核空间也是很有限的。
- 创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多, 因为保存线程状态的过程和调用程序都只是本地过程
三、缺点
- 一个线程阻塞,会阻塞该进程中其他所有的线程。比如:线程发生 I/O 或页面故障引起的阻塞时,如果调用阻塞系统调用则内核由于不知道有多线程的存在,而会阻塞整个进程从而阻塞所有线程,缺页中断也会产生类似的问题。
- 如果一个线程开始运行,那么该进程中其他线程就不能运行,除非第一个线程自动放弃 CPU 。因为在一个单独的进程内部,没有时钟中断,所以不能用轮转调度(轮流)的方式调度线程。
- 还有一个缺点就是对于线程的调度方面,这个其实既是缺点也是优点,说是缺点是因为,不像内核线程的调度那样,由时钟中断来控制,在用户线程中我们必须自己手动编写调度的代码,这会极大的增加我们代码的复杂度。那我为什么说同时也是一种优点呢?那是因为,线程调度的控制权掌握在了我们自己手中,我可以自己定制相应的调度策略。
内核级线程
一、概述
在内核中有一个用来记录系统中所有线程的线程表(TCB,进程表PCB),当某个线程希望创建一个新线程或撤销一个已有线程时,它进行一个系统调用,这个系统调用通过对线程表的更新完成线程的创建或撤销工作。
现在主流的操作系统对于线程的实现,大多采用这种线程模型,比如 Windows、Linux 等。
二、优点
- 当一个线程阻塞时,内核根据选择,可以运行同一个进程中的其它线程或其他进程中的线程。
- 由内核来调(借助于时钟中断),开发者无须关心调度的实现。
三、缺点
- 在内核中创建和撤销线程的开销比较大,速度慢
二者的对比
关于用户级线程和内核级线程这两种线程模型的对比,个人认为主要可以从调度、开销、性能这三个角度来看待。
- 调度:对于用户级线程,操作系统内核不可感知,调度需要由开发者自己实现,内核级线程则与之相反,开发者可以做个甩手掌柜,将调度全权交由操作系统内核来完成。
- 开销:在前面介绍用户级线程的优点时,也提到了,在用户空间创建线程的开销相比之下会比内核空间小很多。
- 性能:用户级线程的切换发生在用户空间,这样的线程切换至少比陷入内核要快一个数量级,不需要陷入内核、不需要上下文切换、不需要对内存高速缓存进行刷新,这就使得线程调度非常快捷。
在早期的操作系统中有不支持线程的,都是使用用户线程来实现的,现在都支持线程了,大多数都使用轻量级进程去映射内核线程的手段来实现多线程技术,包括常见的 Windows 和 Linux 就这种一对一的线程模型。