C - 线程创建和子进程创建中的系统调用有什么区别



如何在系统中实现线程?我知道子进程是使用 fork() 调用创建的而且线是轻量级的。线程的创建与子进程的创建有何不同?

线程是使用 clone() 系统调用创建的,该调用可以创建一个与其父进程共享内存空间和一些内核控制结构的新进程。这些进程称为 LWP(轻量级进程),也称为内核级线程。

fork()创建一个新进程,该进程最初与其父进程共享内存,但页面是写入时复制的,这意味着当原始内存页的内容发生更改时,将创建单独的内存页。因此,父进程和子进程都不能再更改彼此的内存,并且它们实际上作为单独的进程运行。此外,新分叉的子进程是一个成熟的进程,具有独立的内核控制结构。

每个进程都有自己的地址空间 ,即进程可以访问的虚拟地址范围。当一个新进程被分叉时,必须制作所有涉及的资源的副本。分叉完成后,子级和父级拥有自己独特的地址空间以及其中涉及的所有资源。当然,这是一项性能密集型操作。

虽然同一进程中的所有线程共享相同的地址空间,因此当生成新线程时,每个线程只需要自己的堆栈并且不会像进程那样重复所有资源。因此,线程的生成对性能的消耗要低得多。

当然,这两种操作不能也不应该进行比较,因为两者都为不同的需求提供了本质上不同的功能。

嗯,它有很大的不同,首先子进程在某种程度上是父程序的副本,并且所有变量都是重复的,并且您通过其PID将子进程与父程序区分开来。线程就像新程序,它们与主程序同时运行(由于操作系统对CPU的切片时间,它看起来像同时运行)。线程可以在程序中使用全局变量,但它们不会将重复作为进程。因此,使用线程比使用新进程便宜得多。

好吧,您已经阅读了重要部分,现在这里有一些幕后的东西:

当前的实现中(当前是指过去几十年),进程内存在技术上不会在分叉后立即复制。只读部分只是在两个进程之间共享(因为它们无论如何都无法更改),当然,共享库的只读部分也是如此。但最重要的是,所有可写的东西最初也只是共享的。但是,它以写保护的方式共享,一旦写入子进程内存(例如,通过递增变量),内核中就会生成页面错误,这才导致内核实际复制相应的页面(然后进行修改)。

这种伟大的优化,称为"写入时复制",导致子进程通常不会真正消耗与其父进程一样多的(物理)内存。但是,对于程序开发人员(和用户)来说,它是完全透明的。

最新更新