【发布时间】:2012-06-28 11:00:13
【问题描述】:
线程的实现是如何在系统中完成的? 我知道子进程是使用 fork() 调用创建的 一根线很轻。线程的创建与子进程的创建有何不同?
【问题讨论】:
标签: c multithreading unix process
线程的实现是如何在系统中完成的? 我知道子进程是使用 fork() 调用创建的 一根线很轻。线程的创建与子进程的创建有何不同?
【问题讨论】:
标签: c multithreading unix process
线程是使用clone() 系统调用创建的,它可以创建一个与其父进程共享内存空间和一些内核控制结构的新进程。这些进程称为 LWP(轻量级进程),也称为内核级线程。
fork() 创建一个新进程,最初与其父进程共享内存,但页面是写时复制的,这意味着当原始页面的内容发生更改时会创建单独的内存页面.因此,父进程和子进程都不能再更改彼此的内存,并且它们有效地作为单独的进程运行。此外,新分叉的子进程是一个成熟的进程,具有独立的内核控制结构。
【讨论】:
clone(2) 并使用 POSIX 线程,除非您从事系统编程。内核接口可以(并且确实)及时改变。 pthreads API 应该更稳定。
每个进程都有自己的地址空间,也就是进程可以访问的虚拟地址范围。当一个新进程分叉时,必须制作所有相关资源的副本。分叉完成后,子节点和父节点拥有各自不同的地址空间以及其中涉及的所有资源。当然,这是一个性能密集型操作。
虽然同一进程中的所有线程共享相同的地址空间,所以当一个新线程产生时,每个线程只需要自己的堆栈,并且不会像进程那样重复所有资源。因此,线程的产生对性能的影响要小得多。
当然,这两个操作不能也不应该进行比较,因为它们针对不同的需求提供了本质上不同的功能。
【讨论】:
它非常不同,首先子进程在某种程度上是父程序的副本,并且所有变量都重复,并且您通过其 PID 将子进程与父进程区分开来。线程就像新程序,它们与主程序同时运行(看起来是同时运行的,由于 os 对 cpu 时间的切片)。线程可以在程序中使用全局变量,但它们不会像进程一样重复。所以使用线程比使用新进程要便宜得多。
【讨论】:
您已经阅读了重要部分,现在是幕后的东西:
在当前的实现中(当前意味着过去几十年),从技术上讲,进程内存不会在分叉后立即复制。只读部分只是在两个进程之间共享(因为它们无论如何都不能更改),当然还有共享库的只读部分。但最重要的是,所有可写的东西最初也只是共享的。然而,它是以写保护的方式共享的,一旦你写入子进程内存(例如通过增加一个变量),内核中就会产生一个页面错误,这只会导致内核 实际上复制相应的页面(然后发生修改)。
这种称为“写入时复制”的出色优化导致子进程通常不会真正消耗与其父进程一样多的(物理)内存。然而,对于程序开发者(和用户)来说,它是完全透明的。
【讨论】: