Linux 用户级线程和内核级线程 - Go语言中文社区

Linux 用户级线程和内核级线程


写在前边的话,本文图片均转自http://www.51cto.com

目录

1、用户级线程(ULT,UserLevel Thread)

2、内核级线程(KST,Kernel Supported threads)

3、三种实现模型/组合方式

(1) 多对一(用户级或应用程序级线程)

(2) 一对一(内核级线程)

(3) 多对多(用户级和内核级混合线程)

(4) 三种实现模型/组合方式的对比


        在有的系统中,特别是一些数据库管理系统如IBM的infomix系统,所实现的是用户级线程(User Level Threads,ULT);而另一些系统如(Mac os的前身Macintosh 和OS/2操作系统)所实现的是内核支持线程 ( Kernel Supported threads, KST);还有一些是Solaris操作系统,则同时实现了这两种类型的线程。

1、用户级线程(ULT,UserLevel Thread)

        不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供的创建、同步、调度和管理线程的函数来控制用户线程。另外,用户线程是应用进程利用线程库创建和管理,不依赖于操作系统核心。不需要用户态/核心态切换,速度快。操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。

        用户进程ULT仅存在于用户空间中。对于这种线程的创建、撤销、线程之间的同步和通信等功能,都无需系统调用来实现。对于同一进程的线程之间切换仍然是不需要内核支持的。所以呢,内核也完全不会知道用户级线程的存在。但是有一点必须注意:设置了用户级线程的系统,其调度仍然是以进程为单位进行的。

        用户级线程仅存在于用户空间中,与内核无关;就内核而言,它只是管理常规的进程—单线程进程,而感知不到用户级线程的存在;每个线程控制块都设置在用户空间中,所有对线程的操作也在用户空间中由线程库中的函数完成,无需内核的帮助;设置了用户级线程的系统,其调度仍是以进程为单位进行的。

        优点:

  • 线程切换不需要转换到内核空间,节省了宝贵的内核空间;

  • 调度算法可以是进程专用,由用户程序进行指定;

  • 用户级线程实现和操作系统无关;​​​​​​

        缺点:

  • 系统调用阻塞,同一进程中一个线程阻塞和整个进程都阻塞了。

  • 一个进程只能在一个cpu上获得执行

2、内核级线程(KST,Kernel Supported threads)

        内核级线程又称内核支持的线程或轻量级进程。由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。Windows NT和2000/XP 支持内核线程。

        对于一切的进程,无论是系统进程还是用户进程,进程的创建和撤销,以及I/O操作都是利用系统调用进入到内核,由内核处理完成,所以说在KST下,所有进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。内核空间实现还为每个内核支持线程设置了一个线程控制快,内核是根据该控制快而感知某个线程是否存在,并加以控制。

        内核支持线程是在核心空间实现的;内核为每个线程在核心空间中设置了一个线程控制块,用来登记该线程的线程标识符、寄存器值、状态、优先级等信息;所有对线程的操作,如创建、撤消和切换等,都是通过系统功能调用由内核中的相应处理程序完成;设置了内核支持线程的系统,其调度是以线程为单位进行的。

        优点:

  • 在多处理器上,内核可以调用同一进程中的多个线程同时工作;

  • 如果一个进程中的一个线程阻塞了,其他线程仍然可以得到运行;

        缺点:

  • 对于用户线程的切换代价太大,在同一个线程中,从一个线程切换到另一个线程时,需要从用户态,进入到内核态并且由内核切换。因为线程调度和管理在内核实现。

        内核线程实际上是直接由内核本身启动的进程。Linux的内核线程是由kernel_thread()函数在内核态下创建的。(将创建时得到的函数永远执行下去,由一个循环组成,在需要的时候,内核线程将被唤醒执行)。

        当前系统中有一些工作是由内核线程完成的:

  • 周期性地将修改的内存页与页来源块设备同步

  • 如果内存页很少使用,则写入交换区

  • 管理延时动作

  • 实现文件系统的事务日志

  • 执行软中断(ksoftirqd)

        内核线程可能用于两种场景:

  • 启动一个内核线程,然后一直处于等待状态直到被唤醒以完成某种服务

  • 启动一个周期性运行的内核线程,以检查特定资源的使用情况,并作出适当的反映

        内核线程由内核自身生成,其特点在于:

  • 它们在内核态执行,而不是用户态。

  • 它们只可以访问虚拟地址空间的内核部分(高于TASK_SIZE的所有地址),但不能访问用户空间。

        内核线程池不会被销毁和重建,这些线程总是位于系统中。它们会在必要时分配给不同的用户级线程,而不是当创建新的用户级线程时就创建一个新的内核线程,而纯内核级线程被创建时,就会创建一个新的内核线程。只对池中的每个线程创建上下文。有了内核线程和混合线程,操作系统分配一组处理器内核,进程的线程可以在这些处理器内核之上运行。线程只能在为它们所属线程指派的处理器内核上运行。

3、三种实现模型/组合方式

(1) 多对一(用户级或应用程序级线程)

 

多对一(用户级或应用程序级线程)

        用户级线程驻留在用户空间或模式。运行时库管理这些线程,它也位于用户空间。它们对于操作系统是不可见的,因此无法被调度到处理器内核。每个线程并不具有自身的线程上下文。因此,就线程的同时执行而言,任意给定时刻每个进程只能够有一个线程在运行,而且只有一个处理器内核会被分配给该进程。对于一个进程,可能有成千上万个用户级线程,但是它们对系统资源没有影响。运行时库调度并分派这些线程。如同在图中看到的那样,库调度器从进程的多个线程中选择一个线程,然后该线程和该进程允许的一个内核线程关联起来。内核线程将被操作系统调度器指派到处理器内核。用户级线程是一种"多对一"的线程映射。

(2) 一对一(内核级线程)

 

一对一(内核级线程)

       

        内核级线程驻留在内核空间,它们是内核对象。有了内核线程,每个用户线程被映射或绑定到一个内核线程。用户线程在其生命期内都会绑定到该内核线程。一旦用户线程终止,两个线程都将离开系统。这被称作"一对一"线程映射,如图所示。操作系统调度器管理、调度并分派这些线程。运行时库为每个用户级线程请求一个内核级线程。操作系统的内存管理和调度子系统必须要考虑到数量巨大的用户级线程。您必须了解每个进程允许的线程的最大数目是多少。操作系统为每个线程创建上下文。线程的上下文将在本章稍后部分介绍。进程的每个线程在资源可用时都可以被指派到处理器内核。

(3) 多对多(用户级和内核级混合线程)

 

多对多(用户级和内核级混合线程)

       

        混合线程实现是用户线程和内核线程的交叉,使得库和操作系统都可以管理线程。用户线程由运行时库调度器管理,内核线程由操作系统调度器管理。在这种实现中,进程有着自己的内核线程池。可运行的用户线程由运行时库分派并标记为准备好执行的可用线程。操作系统选择用户线程并将它映射到线程池中的可用内核线程。多个用户线程可以分配给相同的内核线程。在图中,进程A在它的线程池中有两个内核线程,而进程B有3个内核线程。进程A的用户线程2和3被映射到内核线程(2)。进程B有5个线程,用户线程1和2映射到同一个内核线程(3),用户线程4和5映射到内核同一个内核线程(5)。当创建新的用户线程时,只需要简单地将它映射到线程池中现有的一个内核线程即可。这种实现使用了"多对多"线程映射。该方法中尽量使用多对一映射。很多用户线程将会映射到一个内核线程,就像您在前面的示例中所看到的。因此,对内核线程的请求将会少于用户线程的数目。

(4) 三种实现模型/组合方式的对比

  • 虽然多对一模型对创建用户级线程的数目并没有限制,但这些线程在同一时刻只能有一个被执行。

  • 一对一模型可以获得高并发性,但因耗费资源而使线程数会受到限制。

  • 多对多模型具有多对一和一对一两种模型的优势,用户可以创建所需要的用户级线程,通过分配适当数目的内核级线程获得并发执行的优势并节省系统资源。

写在后边的话,本文图片均转自http://www.51cto.com

 

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/itakyubi/article/details/100024284
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-12 18:53:50
  • 阅读 ( 1241 )
  • 分类:Linux

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢