6

我对多处理器机器中 posix 线程的并发性有一些疑问。我在 SO 中发现了类似的问题,但没有找到确凿的答案。

以下是我的理解。我想知道我是否正确。

  1. Posix 线程是用户级线程,内核不知道它。

  2. 内核调度程序将 Process(及其所有线程)视为一个调度实体。依次选择运行哪个线程的是线程库。它可以在可运行的线程中分割内核给定的 cpu 时间。

  3. 用户线程可以在不同的 cpu 内核上运行。即让线程 T1 和 T2 由 Process(T) 创建,然后 T1 可以在 Cpu1 中运行,T2 可以在 Cpu2 中运行,但它们不能同时运行

请让我知道我的理解是否正确。

谢谢...

4

3 回答 3

9

既然您用“Linux”标签标记了您的问题,我将根据 linux 下的标准 pthreads 实现来回答它。如果您谈论的是在虚拟机/语言级别而不是操作系统上安排的“绿色”线程,那么您的答案大多是正确的。但我下面的评论是关于 Linux pthreads 的。

1) Posix 线程是用户级线程,内核不知道。

不,这肯定是不正确的。Linux 内核和 pthreads 库一起工作来管理线程。内核负责上下文切换、调度、内存管理、高速缓存管理等。当然还有其他的管理在用户级别完成,但是没有内核,pthread 的大部分功能都会丢失。

2)内核调度器将进程(及其所有线程)视为一个调度实体。依次选择运行哪个线程的是线程库。它可以在可运行的线程中分割内核给定的 cpu 时间。

不,内核将每个进程线程视为一个实体。它有自己的时间片规则,考虑了进程(和进程优先级),但每个子进程线程都是一个可调度的实体。

3) 用户线程可以在不同的 cpu 内核上运行。即让线程 T1 和 T2 由 Process(T) 创建,然后 T1 可以在 Cpu1 中运行,T2 可以在 Cpu2 中运行,但它们不能同时运行。

不会。多线程程序需要并发执行。这就是为什么同步和互斥锁如此重要,以及为什么程序员要忍受多线程编程的复杂性。


向您证明这一点的一种方法是查看pswith-L选项的输出以显示关联的线程。 ps通常将多个线程进程包装在一行中,但-L您可以看到内核为每个线程都有一个单独的虚拟进程 ID:

ps -ef | grep 20587
foo    20587     1  1 Apr09 ?        00:16:39 java -server -Xmx1536m ...

相对

ps -eLf | grep 20587
foo    20587     1 20587  0  641 Apr09 ?    00:00:00 java -server -Xmx1536m ...
foo    20587     1 20588  0  641 Apr09 ?    00:00:30 java -server -Xmx1536m ...
foo    20587     1 20589  0  641 Apr09 ?    00:00:03 java -server -Xmx1536m ...
...

我不确定 Linux 线程是否仍然这样做,但历史上 pthreads 使用clone(2)系统调用来创建自身的另一个线程副本:

与 fork(2) 不同,这些调用允许子进程与调用进程共享其部分执行上下文,例如内存空间、文件描述符表和信号处理程序表。

fork(2)这与创建另一个完整进程时使用的不同。

于 2012-04-10T13:20:38.033 回答
5

POSIX 没有指定如何将创建的线程pthread_create调度到处理器内核。这取决于实施。

但是,我希望在质量实现中具有以下内容,当前版本的 linux 就是这种情况:

  • 线程是完整的内核线程,由内核调度
  • 来自同一进程的线程可以在不同的处理器上同时运行

即,所有 3 条编号语句对于当前的 linux 实现都是错误的,但理论上对于也符合 POSIX 的另一个实现来说可能是正确的。

于 2012-04-10T13:24:42.280 回答
0

大多数 POSIX 实现使用操作系统支持来提供线程功能——它们包装了管理线程所需的系统调用。因此,线程的行为重新。调度等取决于底层操作系统。

因此,在大多数现代操作系统上:

  1. 具有 POSIX 线程的进程与具有多个线程的任何其他进程对内核没有什么不同。

  2. 内核调度程序调度线程,而不是进程。“进程”通常被视为具有代码、内存管理、配额、审计和安全权限的高级构造,但不具有执行权限。除非线程运行其代码,否则进程无法执行任何操作,这就是为什么在创建进程时会同时创建“主线程”,否则不会运行任何东西。操作系统调度算法可以使用线程运行的进程作为参数之一来决定接下来运行哪一组就绪线程——将一个线程与来自同一进程的一个线程交换出来更便宜——但它不必这样做。

    当准备好的线程多于运行它们的内核时,将内核给定的 cpu 时间切片在可运行线程之间是 OS 计时器中断的副作用。任何经常不得不求助于(呃!-我讨厌这个词)的机器,“时间切片”应该被认为是超载的,应该有更多的 CPU 或更少的工作。理想情况下,线程应该只在由另一个线程或 IO 驱动程序发出信号时才准备就绪,而不是因为 OS 计时器中断已决定运行它来代替仍然可以做有用工作的另一个线程。

  3. 他们只是可以同时运行。如果两个线程准备就绪并且有两个核心,则将线程分派到两个核心上。它们是否来自同一进程并不重要。

于 2012-04-10T13:50:20.400 回答