Pthread库实际上是一种用户级线程解决方案吗?

61

我的问题可能不够清晰,因为我不知道如何明确定义。

我了解Pthread是符合POSIX标准的线程库(关于POSIX,可参见维基百科:http://en.wikipedia.org/wiki/Posix)。它在类Unix操作系统中可用。

关于线程,我了解到有三个不同的模型:

用户级线程:内核并不知道它。用户自己创建/实现/销毁线程。

内核级线程:内核直接支持一个进程中的多个控制线程。

轻量级进程(LWP):由内核调度,但可以与用户线程绑定。

你看到我的疑惑了吗?当我调用pthread_create()来创建一个线程时,我创建了一个用户级线程吗?我猜是这样的。那么,我可以说,Pthread提供了一种用户级别的线程解决方案吗?它无法操纵内核/LWP吗?

6个回答

37

@paulsm4 我对你的评论“内核知道所有事情”持怀疑态度。在这种特定的用户级线程上下文中,内核并不知道正在发生这样的事情。用户级线程的调度是由用户自己通过提供的接口库来维护的,内核最终只分配一个内核线程给整个进程。内核将处理该进程作为单线程,并且任何一个线程的阻塞调用都会导致该进程的所有线程被阻塞。

参考http://www.personal.kent.edu/~rmuhamma/OpSystems/Myos/threads.htm

如果不使用内核线程,这种情况就会发生。反之亦然。如果在用户空间处理此问题,最终只能使用一个核心,因为用户空间无法控制核心,也无法在没有内核交互的情况下在核心上安排任务。 - Sebi2020

27
在Linux中,pthread实际上是作为轻量级进程实现的。内核(v2.6+)实际上是使用NPTL实现的。让我引用维基百科的内容:

NPTL是一种所谓的1×1线程库,即由用户创建的线程(通过pthread_create()库函数)与内核中的可调度实体(在Linux情况下为任务)一一对应。这是可能的最简单的线程实现。

因此,在Linux内核中,pthread实际上是作为内核线程实现的。

3
这应该是被接受的答案。在Linux中,Pthreads是使用NPTL实现的,它实际上是一种一对一的线程模型。每个用户级线程创建时,都会有一个与之关联的内核级线程。这意味着使用NPTL实现的Pthreads可以利用多核CPU。 - dantebarba
@dantebarba:Junji Zhi是正确的(我昨天点赞了他的回答,也在多年前更新了我的回复),而你是错误的。重要提示:1)Pthreads只是一个接口。实现会因环境而异。2)Linux实现的“线程”与“进程”并不一定对应于通常在一般操作系统教材中所描绘的内容。3)具体来说,Linux pthreads实现通常使用Linux NTPL,"...一个所谓的1x1线程库"。 - paulsm4
1
你只是在回应我之前评论中所说的话...另外,我不是唯一一个认为你的回答误导人的人。你明确地说“内核知道一切”,这在N:1线程模型上是不正确的。NPTL是一种1-1模型的实现,并不意味着所有实现都应该以相同的方式运行。 - dantebarba

15

pthreads本身并不是一个线程库。pthreads是一个特定线程库使用可用的并发资源实现的接口。所以,在linux、bsd、solaris等操作系统上都有pthread实现,虽然接口(头文件和调用意义)相同,但每个实现的具体实现方式是不同的。

因此,在不同的操作系统和pthread库实现中,pthread_create在内核线程对象方面的实际作用也是不同的。初步估计,你不需要知道这些(这是pthread抽象允许你不必了解的内容)。最终,你可能需要看“幕后”,但对于大多数pthread用户来说,这是不必要的。

如果你想了解特定操作系统上的特定pthread实现的具体做法,你需要澄清你的问题。例如,Solaris和Linux做的事情是非常不同的。


11

Q: 我了解Pthread是符合POSIX标准的线程库。

A: 是的。实际上,“Pthreads”代表“Posix线程”: http://en.wikipedia.org/wiki/Pthreads

Q: 它在类Unix操作系统中可用。

A: 实际上,它适用于许多不同的操作系统...包括Windows、MacOS...当然还有Linux、BSD和Solaris。

Q: 关于线程,我读到有三种不同的模型。

现在你有点模糊了。“线程”是一个非常通用的术语。有许多许多不同的模型。而且有许多不同的方式可以描述和/或实现“线程”。包括像Java线程模型或Ada线程模型这样的东西。

Q: 当我调用pthread_create()创建一个线程时,我创建了一个用户级线程吗?

A: 是的:你在用户空间中做的几乎所有事情都是在你自己的私有“用户空间”中“受保护”的。

Q: 用户级线程:内核不知道它。

A: 不是的。内核知道一切 :)

Q: 内核级线程:内核直接支持进程中的多个控制线程。

A: 是的,有这样一种东西叫做“内核线程”。

而且,恰好Linux广泛使用内核线程。例如,在Linux系统中,每个进程都是一个“内核线程”。每个用户创建的pthread也被实现为一个新的“内核线程”。工作线程(对任何用户级进程完全不可见)也是如此。

但这是一个高级主题,您不需要理解就可以有效地使用pthread。以下是一本详细讨论了此主题和许多其他主题的好书:

Linux Kernel Development, Robert Love

记住:“Pthreads”是一个接口。它的实现取决于平台。Linux使用内核线程;Windows使用Win32线程等。

=========================================================================== 附录:

由于人们似乎仍然在访问这个旧帖子,我认为引用这篇文章可能会有用:

https://dev59.com/0Gkv5IYBdhLWcg3wvDJF#11255174

Linux通常使用两种pthread实现: LinuxThreadsNative POSIX Thread Library(NPTL), 尽管前者已经大部分过时。从2.6开始,内核提供了NPTL,它更接近SUSv3标准,并且在有许多线程时表现得更好。

您可以在shell下使用命令查询pthread的特定实现:

getconf GNU_LIBPTHREAD_VERSION

您还可以在The Linux Programming Interface中获取更详细的实现差异。

“Pthreads”是一个基于Posix标准的。 pthreads库的实现会因平台和库而异。


32
你在制造混淆吗?1.原贴作者从未询问过关于Linux的具体细节2.内核并不知道所有事情,特别是在用户级线程的情况下,因为它们不是由内核调度的,而是由库——在这种情况下是Pthreads——“切换”的。3.“线程”这个术语是通用的。没错,但问题更多地涉及线程在操作系统和应用程序接口中的抽象概念,答案应该是有关这些抽象概念的内容。 - ultimate cause
13
这个答案完全是错误的。内核并不知道用户空间线程;如果创建一个线程需要通过系统调用通知内核,那么你的线程就不再是“用户空间”线程了。正确的答案包括https://dev59.com/2moy5IYBdhLWcg3wUcRL#12169068和https://dev59.com/2moy5IYBdhLWcg3wUcRL#27581327;https://dev59.com/2moy5IYBdhLWcg3wUcRL#8639239只表达了这个答案的正确部分(但缺少了使其他答案对OP真正有帮助的Linux细节)。 - Quuxplusone
1
每个Linux进程如何成为内核线程?在Linux中,进程被定义为struct task_struct结构中的PCB(进程控制块)。 - trinity420
2
这个答案非常误导人。用户级线程对内核不可见。这就是N:1线程模型的全部内容。你可以在每本基本操作系统概念书上阅读到这一点,比如Silberschatz第7版或Stallings第7版。此外,就像第一个用户描述的那样,有三种线程模型:N:1模型:多个用户级线程映射到一个内核级线程。 1:1模型:一个用户级线程对应一个内核级线程。 N:M模型:一个用户级线程映射到一个轻量级进程,该轻量级进程映射到多个内核级线程。 - dantebarba
1
老兄 - 事实是 Linux 做事情"有些不同"(有很好的理由,带来了非常有利的结果)。所以你在"每个基本操作系统概念书"上读到的内容可能会或可能不会完全适用。是的,我也读过 Stallings 的书。也许你应该阅读Love,3rd Ed,然后再重新阅读 Stallings 的书;)或者只需为下面FinJunji Zhi的回答点赞即可。 - paulsm4

6
我发现之前的答案不够令人满意或清晰,因此我来试一下:

当你打电话时

pthread_create(...)

您始终创建新的用户级线程。假设有操作系统,就始终存在一个或多个内核线程...但让我们深入了解一下:
根据《操作系统概念》第10版,我们应该关注的实际分类(当涉及到线程库时)是如何将用户级线程映射到内核线程上(这才是问题真正的意思)。
模型有:一对一(一个进程中的每个用户级线程都映射到不同的内核线程),多对一(线程库是“用户级”的,因此单个进程中的所有不同线程都映射到单个内核线程,并且线程数据结构、上下文切换等在用户级别处理,而不是由操作系统处理[这意味着如果线程在某个I/O调用上阻塞,整个进程可能会潜在地阻塞]),以及多对多(介于两者之间,显然用户级线程的数量大于或等于它被映射到的内核线程数)。
现在,pthread是一种规范而不是一种实现,其实现取决于编写它的操作系统。它可以是这些模型之一(请注意,“多对多”非常灵活)。
所以,例如,在Linux和Windows上(多年来最流行的操作系统,在那里模型是“一对一”),实现是“一对一”。

0

Pthreads只是线程库的标准化接口。创建操作系统线程还是轻量级线程取决于您使用的库。尽管如此,我的第一个猜测是您的线程是“真正”的操作系统级别线程。


1
这个答案在技术上似乎是正确的,但并没有提供任何有用的信息。 - Quuxplusone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接