用户级和内核支持的线程之间的区别?

时间:2013-04-13 03:23:31

标签: multithreading process operating-system theory

我一直在查看基于此主题的一些注释,虽然我对一般的线程有所了解,但我并不确定用户级和内核级线程之间的差异

我知道进程基本上由多个线程或单个线程组成,但是前面提到的两种类型的线程是什么?

根据我的理解,内核支持的线程可以访问内核以进行系统调用和用户级线程无法使用的其他用途。

那么,用户级线程是否只是程序员创建的线程,然后利用内核支持的线程执行由于其状态而无法正常执行的操作?

6 个答案:

答案 0 :(得分:73)

编辑:这个问题有点混乱,所以我用两种不同的方式回答。

OS级别线程与绿色线程

为清楚起见,我通常说“操作系统级线程”或“本机线程”而不是“内核级线程”(我在下面的原始答案中与“内核线程”混淆。)创建操作系统级线程并由操作系统管理。大多数语言都支持它们。 (C,最近的Java等)它们非常难以使用,因为您100%负责预防问题。在某些语言中,即使是本机数据结构(例如Hashes或Dictionaries)也会在没有额外锁定代码的情况下中断。

与OS线程相反的是由您的语言管理的green thread。这些线程根据语言(C中的协同程序,Go中的goroutines,Ruby中的光纤等)给出了各种名称。这些线程只存在于您的语言中,而不存在于您的操作系统中因为语言选择上下文切换(即在语句的末尾),它会阻止TONS的微妙竞争条件(例如,看到部分复制的结构,或者需要锁定大多数数据结构)。程序员看到“阻塞”调用(即data = file.read()),但语言将其转换为对操作系统的异步调用。然后,该语言允许其他绿色线程在等待结果时运行。

绿色线程对于程序员来说简单得多,但它们的性能各不相同:如果你有很多线程,绿色线程可以更好地用于CPU和RAM。另一方面,大多数绿色线程语言无法利用多个核心。 (你甚至不能再购买单核电脑或手机了!)。一个坏的库可以通过阻止OS调用来暂停整个语言。

两者中最好的是每个CPU有一个OS线程,并且许多绿色线程神奇地移动到OS线程上。像Go和Erlang这样的语言可以做到这一点。

  

系统调用和用户级线程无法使用的其他用途

这只是一半。是的,如果你自己调用操作系统(即做一些阻塞的操作),你很容易引起问题。但是语言通常有替换,所以你甚至都没注意到。这些替换确实会调用内核,与您的想法略有不同。

内核线程与用户线程

编辑:这是我的原始答案,但它是关于用户空间线程与仅​​内核线程,(事后看来)可能不是问题。

用户线程和内核线程完全相同。 (您可以通过查看/ proc /看到内核线程也在那里。)

用户线程是执行用户空间代码的线程。但它可以随时调用内核空间。它仍然被认为是一个“用户”线程,即使它正在以更高的安全级别执行内核代码。

内核线程是仅运行内核代码并且与用户空间进程无关的线程。这些就像“UNIX守护进程”,除了它们是仅内核的守护进程。所以你可以说内核是一个多线程程序。例如,有一个用于交换的内核线程。这会强制所有交换问题“序列化”为单个流。

如果用户线程需要某些东西,它将调用内核,这会将该线程标记为休眠。之后,交换线程找到数据,因此它将用户线程标记为可运行。后来,“用户线程”从内核返回到用户空间,好像什么都没发生一样。

实际上,所有线程都是从内核空间开始的,因为clone()操作发生在内核空间中。 (在你可以'返回'到用户空间的新进程之前,还有很多内核会计要做。)

答案 1 :(得分:14)

在我们进行比较之前,让我们先了解一下线程是什么。线程是独立进程域内的轻量级进程。它们是必需的,因为流程繁重,消耗大量资源,更重要的是,

  

两个独立的进程无法共享内存空间。

我们假设你打开一个文本编辑器。它是在存储器中执行的独立进程,具有单独的可寻址位置。在此过程中您需要许多资源,例如插入图形,拼写检查等。为这些功能中的每一个创建单独的进程并在内存中独立维护它们是不可行的。为避免这种情况,

  

可以在单个进程中创建多个线程,也可以   共享一个共同的内存空间,在一个进程中独立存在。

现在,回到你的问题,一次一个。

  

我不确定用户级和内核级线程之间的区别。

根据其执行域,线程大致分为用户级线程内核级线程。还有一些情况是一个或多个用户线程映射到一个或多个内核线程

- 用户级线程

用户级线程主要位于应用程序级别,应用程序创建这些线程以维持其在主内存中的执行。除非必要,否则这些线程与内核线程隔离。

这些更容易创建,因为它们不必引用许多寄存器,并且上下文切换比内核级线程快得多。

用户级线程,主要是在应用程序级别引起更改,内核级别线程继续按自己的进度执行。

- 内核级别主题

这些线程大多独立于正在进行的进程,并由操作系统执行。

操作系统需要这些线程来执行内存管理,进程管理等任务。

由于这些线程维护,执行和报告操作系统所需的进程;内核级线程的创建和管理成本更高,这些线程的上下文切换速度很慢。

大多数内核级线程都不能被用户级线程抢占。

MS DOS written for Intel 8088 didn't have dual mode of operation. Thus, a user level process had the ability to corrupt the entire operating system.

- 通过内核线程映射的用户级线程

这可能是最有趣的部分。许多用户级线程映射到内核级线程,后者又与内核进行通信。

一些突出的映射是:

  

一对一

当一个用户级线程仅映射到一个内核线程时。

优点:每个用户线程映射到一个内核线程。即使其中一个用户线程发出阻塞系统调用,其他进程也不会受到影响。

缺点:每个用户线程都需要一个内核线程进行交互,而内核线程的创建和管理成本很高。

  

多对一

当许多用户线程映射到一个内核线程时。

优点:不需要多个内核线程,因为类似的用户线程可以映射到一个内核线程。

缺点:即使其中一个用户线程发出阻塞系统调用,也会阻止映射到该内核线程的所有其他用户线程。

此外,由于内核一次只处理一个内核线程,因此无法实现良好的并发性。

  

多对多

当许多用户线程映射到相同或更少数量的内核线程时。程序员决定有多少用户线程将映射到多少内核线程。一些用户线程可能只映射到一个内核线程。

优点:实现了高水平的并发性。程序员可以决定一些可能发出阻塞系统调用的潜在危险线程,并将它们与一对一映射放在一起。

缺点:内核线程的数量,如果不谨慎决定可以减慢系统速度。

问题的另一部分:

  

内核支持的线程可以访问内核以进行系统调用   和用户级线程无法使用的其他用途。

     

因此,用户级线程只是程序员创建的线程   然后利用内核支持的线程执行操作   由于状态不能正常执行?

部分正确。由于内核线程负责执行OS的进程,因此几乎所有内核线程都可以访问系统调用和其他关键中断。用户线程无法访问其中一些关键功能。例如文本编辑器永远不能拍摄能够更改进程物理地址的线程。但是如果需要,用户线程可以映射到内核线程并发出一些它不能作为独立实体进行的系统调用。然后,内核线程将此系统调用映射到内核,如果认为合适,将执行操作。

答案 2 :(得分:2)

某些开发环境或语言会添加自己的线程,如功能,这些线程是为了利用环境的一些知识而编写的,例如GUI环境可以实现某些线程功能,这些功能在每个事件循环上的用户线程之间切换。游戏库可能会有类似线程的角色行为。有时用户线程就像行为可以用不同的方式实现,例如我经常使用cocoa,并且它有一个定时器机制,每隔x秒执行一次代码,使用几分之一秒,就像一个线程。 Ruby有一个yield函数,就像协作线程一样。用户线程的优点是它们可以在更可预测的时间切换。使用内核线程每次线程再次启动时,它需要加载它正在处理的任何数据,这可能需要一些时间,用户线程可以在完成一些数据处理后切换,所以它不需要要重新加载。我没有遇到与内核线程看起来相同的用户线程,只有像计时器一样的机制,虽然我已经在旧的教科书中读过它们,所以我想知道它们是不是过去比较流行的东西但随着真正的多线程操作系统(现代Windows和Mac OS X)和更强大的硬件的兴起,我想知道它们是否已经失宠了。

答案 3 :(得分:1)

从这里引用:

Kernel-Level Threads

为了使并发便宜,将进程的执行方面分离为线程。这样,操作系统现在可以管理线程和进程。所有线程操作都在内核中实现,并且OS调度系统中的所有线程。操作系统管理的线程称为内核级线程或轻量级进程。 NT:线程 Solaris:轻量级进程(LWP)。

在这种方法中,内核了解并管理线程。在这种情况下,不需要运行系统。内核有一个线程表来跟踪系统中的所有线程,而不是每个进程中的线程表。此外,内核还维护传统的进程表以跟踪进程。操作系统内核提供系统调用以创建和管理线程。

优势:

因为内核完全了解所有线程,所以调度程序可能会决定给具有大量线程的进程比具有少量线程的进程更多的时间。 内核级线程特别适合经常阻塞的应用程序。

缺点:

内核级线程运行缓慢且效率低下。例如,线程操作比用户级线程慢数百倍。 由于内核必须管理和调度线程以及进程。每个线程都需要一个完整的线程控制块(TCB)来维护有关线程的信息。结果,开销很大,内核复杂性也增加了。

用户级线程

内核级线程使并发比进程便宜得多,因为分配和初始化的状态要少得多。但是,对于细粒度的并发,内核级线程仍然会遭受太多开销。线程操作仍然需要系统调用。理想情况下,我们要求线程操作必须与过程调用一样快。内核级线程必须通用才能满足所有程序员,语言,运行时等的需求。对于这种细粒度的并发,我们仍然需要“便宜”的线程。 为了使线程便宜且快速,它们需要在用户级别实现。用户级线程完全由运行时系统(用户级库)管理。内核对用户级线程一无所知,并且像单线程进程一样对其进行管理。用户级线程又小又快,每个线程都由PC,寄存器,堆栈和小线程控制块表示。通过过程调用可以完成创建新线程,在线程之间切换以及同步线程的操作。即没有内核参与。用户级线程比内核级线程快一百倍。

优势:

此技术最明显的优点是,可以在不支持线程的操作系统上实现用户级线程程序包。 用户级线程不需要修改操作系统。 简单表示:每个线程仅由PC,寄存器,堆栈和一个小的控制块表示,所有这些都存储在用户进程地址空间中。 简单管理:这仅意味着创建线程,在线程之间切换以及线程之间的同步都可以在无需内核干预的情况下完成。 快速高效:线程切换并不比过程调用贵。

缺点:

用户级线程不是其他所有方法的完美解决方案,而是一种折衷方案。由于用户级线程对于操作系统是不可见的,因此无法与操作系统很好地集成在一起。结果,Os可能做出较差的决策,例如使用空闲线程调度进程,阻止进程的线程发起I / O的进程,即使该进程还有其他可以运行的线程以及使用持有锁的线程取消调度进程。解决此问题需要内核与用户级线程管理器之间进行通信。 线程与操作系统内核之间缺乏协调。因此,无论进程中有一个线程还是有1000个线程,整个进程都会占用一个时间片。由每个线程放弃对其他线程的控制。 用户级线程需要非阻塞系统调用,即多线程内核。否则,即使进程中剩下可运行的线程,整个进程也会在内核中被阻塞。例如,如果一个线程导致页面错误,则过程将阻塞。

答案 4 :(得分:0)

用户主题: 1.该库提供对线程创建,调度和管理的支持,不受内核的支持。 2.内核不知道用户级线程的创建和调度是在没有内核干预的用户空间中完成的。 3.用户级线程通常很快创建和管理它们但是有缺点。 4.如果内核是单线程的, 那么执行阻塞系统调用的任何用户级线程都会导致 整个进程要阻塞,即使其他线程可以在其中运行 应用。 5.用户线程库包括POSIX Pthreads,Mach C-threads, 和Solaris 2 UI线程。

内核线程: 1.内核在内核空间中执行线程创建,调度和管理。 2.内核线程的创建和管理速度通常比用户线程慢。 3.如果线程执行阻塞系统调用,则内核正在管理线程。 4.在多处理器环境中,内核可以在不同的处理器上调度线程。 5.包括Windows NT,Windows 2000,Solaris 2,BeOS和Tru64 UNIX(以前的数字UN1X) - 支持内核线程。

答案 5 :(得分:0)

用户线程和内核线程之间的区别

用户线程

  • 可以在任何操作系统上运行
  • 线程管理由线程库完成
  • 内核不知道线程的存在
  • 线程库包含用于创建和 破坏线程
  • 这些是应用程序程序员使用的线程 在他们的节目中

内核线程

  • 特定于操作系统
  • 由内核完成的线程管理
  • 应用程序中没有线程管理代码 区域
  • 由操作系统直接支持
  • 如果进程中的一个线程被阻塞,则内核可以 安排同一进程的另一个线程
  • 内核线程的创建和管理速度通常较慢 比用户线程