2013-02-09 46 views
22

所以这里有两个问题。首先,(是的,我已经搜索过,但想澄清),用户线程和内核线程之间有什么区别?简单地说,一个是由用户程序生成的,另一个是由操作系统生成的,后者可以访问特权指令?它们在概念上是相同还是在线程本身存在实际差异?线程:为什么所有用户线程都必须映射到内核线程?

其次,我的问题的真正问题是:我正在使用的这本书说“用户线程和内核线程之间必须存在关系”,并列出这种关系的不同模型。但该书未能清楚解释为什么的用户线程必须总是将映射到特定的内核线程。为什么是这样?

回答

22

A 内核线程是由操作系统维护的线程对象。它是一个能够被处理器调度和执行的实际线程。通常,系统线程是具有权限设置,优先级等的重量级对象。内核线程调度程序负责调度内核线程。

用户程序也可以创建自己的线程调度程序。他们可以创建自己的“线程”并模拟上下文切换以在它们之间切换。但是,这些线程不是内核线程。每个用户线程都不能真正自己运行,而用户线程运行的唯一方式是如果内核线程实际被告知执行包含在用户线程中的代码。也就是说,与内核线程相比,用户线程具有重大优势。它们可以更加轻量级,因为它们不一定需要拥有自己的优先级,可以由单个进程管理(可能有关于需要运行什么线程的更好信息),并且不会创建大量的内核对象用于安全和锁定的目的。

用户线程必须与内核线程关联的原因在于,用户线程本身就是用户程序中的一堆数据。内核线程是系统中真正的线程,因此为了让用户线程取得进展,用户程序必须让其调度程序获取用户线程,然后在内核线程上运行它。用户线程和内核线程之间的映射不一定是一对一(1:1);您可以让多个用户线程共享相同的内核线程(一次只能运行其中一个用户线程),并且您可以拥有一个用户线程,该用户线程在1:n映射中跨不同的内核线程进行轮换。

1

我认为一个真实世界的例子将清除混淆,所以让我们看看Linux中的事情是如何完成的。

首先Linux不区分进程和线程,可以调度的实体在Linux中称为task,由task_struct表示。因此,无论何时执行fork()系统调用,都会创建一个新的task_struct,它保存与新任务关联的数据(或指针)。

所以在Linux世界里,一个内核线程意味着一个task_struct对象(结构)。因为调度程序只知道可以分配给不同CPU(逻辑或物理)的这些实体。换句话说,如果您希望Linux调度程序调度您的过程,则必须创建一个task_struct。

用户线程是由某些执行环境(从现在开始的EE)(如JVM)在内核之外支持和管理的内容。这些EE将为您提供一些功能来创建新线程。

现在让我们来回答你的问题

why a user thread must always be mapped to a specific kernel thread. 

比方说,你用你EE创造了一些线程。最终它们必须由CPU执行,从上面的解释中我们知道你(线程)必须有一个task_struct才能分配给某个CPU。这就是映射必须存在的原因。您的EE有责任创建task_structs。

如果您的EE使用多对一模型,那么它将只为所有线程创建一个task_struct,并且它会将所有这些线程调度到该task_struct。考虑到有一个CPU(task_struct)和许多进程(EE中创建的线程),您的操作系统(EE)会将这些进程复用到单个CPU上。

如果它使用一对一模型,那么EE中创建的每个线程都会有一个task_struct。所以当你在EE中创建一个新线程时,相应的task_struct会在内核中创建。 (如果你希望CPU可以被映射到相应的内核线程上,那么CPU就会被映射到相应的内核线程上)执行它们)。

相关问题