什么时候clone()和fork比pthread更好?

我是这方面的初学者。

我已经学习了fork()vfork()clone()pthreads

我已经注意到, pthread_create()将创build一个线程,这比用fork()创build一个新的进程fork()less。 此外,线程将与父进程共享文件描述符,内存等。

但是什么时候fork()clone()比pthread更好呢? 你可以给我解释给我的真实世界的例子吗?

提前致谢。

Solutions Collecting From Web of "什么时候clone()和fork比pthread更好?"

fork (和company)的优点和缺点是他们创建了一个新的进程,这个进程是现有进程的一个克隆。

这是一个弱点,因为正如你所指出的,创建一个新的过程有相当多的开销。 这也意味着进程之间的通信必须通过一些“批准的”通道(管道,套接字,文件,共享内存区域等)

这是一种力量,因为它提供了父母和孩子之间更多的隔离。 例如,如果一个子进程崩溃了,你可以杀死它并相当容易地启动另一个进程。 相比之下,如果一个子线程死了,最好的办法是杀死它 – 这是不可能确定哪个线程独占的资源,所以你不能清理它。 同样,由于一个进程中的所有线程共享一个公共地址空间,所以遇到问题的一个线程可能会覆盖所有其他线程使用的数据,因此只需要杀死一个线程并不足以清理混乱。

换句话说,使用线程是一种赌博。 只要你的代码全部干净,你可以通过在一个进程中使用多个线程来获得一些效率。 使用多个进程会增加一些开销,但是可以使代码更健壮一些,因为它限制了单个问题可能造成的损害,并且使得关闭和替换进程变得容易问题。

就具体的例子而言,Apache可能是一个很好的例子。 它将在每个进程中使用多个线程,但是为了在发生问题时(特别是其他情况)限制损害,它会限制每个进程的线程数量,并且还可以产生多个并行运行的独立进程。 例如,在一个体面的服务器上,你可能有8个进程,每个进程有8个线程。 大量的线程帮助大部分I / O绑定任务中的大量客户端服务,并将其分解为进程意味着如果出现问题,它不会突然变得完全无响应,并且可以关闭并重新启动一个进程而不会损失太多。

clone(2)是Linux特有的系统调用,主要用于实现线程(特别是用于pthread_create )。 有了各种各样的论点, clone也可以有一个类似fork(2)的行为。 很少有人直接使用clone ,使用pthread库更便于携带。 你可能需要直接调用clone(2)系统调用,只有当你正在实现自己的线程库 – Posix线程的竞争者 – 这是非常棘手的(特别是因为锁定可能需要使用futex(2)系统调用机器调谐汇编代码例程,请参阅futex(7) )。 你不想直接使用clonefutex因为pthreads使用起来更简单。

(其他pthread函数需要在pthread_create期间在clone之后在libpthread.so内部完成一些记录)

正如Jonathon回答的,进程有自己的地址空间和文件描述符集。 一个进程可以执行一个新的可执行程序execve系统调用,基本上初始化地址空间,堆栈和寄存器启动一个新的程序(但是文件描述符可以保留,除非使用关闭执行标志,例如通过O_CLOEXEC 开放 )。

在类Unix系统上, 所有进程(除了第一个进程,通常是init的pid 1)都是由fork创建的(或者像vfork这样的变体;你可以,但是不希望以这种方式使用clone ,像fork )。

(从技术上讲,在Linux上,有一些你可以忽略的奇怪异常,特别是内核进程或线程,以及像/sbin/hotplug这样的内核启动的启动)

forkexecve系统调用是Unix进程创建的核心(带有waitpid和相关的系统调用)。

多线程进程有几个线程(通常由pthread_create创建)都共享相同的地址空间和文件描述符。 当你想要在同一个地址空间内的同一个数据上并行工作时使用线程,但是你应该关心同步和锁定。 阅读pthread教程了解更多信息。

我建议你阅读一本好的Unix编程书籍,比如Advanced Unix Programming和/或(免费提供的) Advanced Linux Programming

这些是完全不同的东西。 fork()创建一个新的进程 。 pthread_create()创建一个新的线程,它在相同进程的上下文中运行。

线程共享相同的虚拟地址空间,内存(好或坏),打开的文件描述符集等等。

进程(基本上)是完全独立的,不能互相修改。

你应该阅读这个问题:

  • 进程和线程有什么区别?

至于一个例子,如果我是你的shell(例如bash ),当你输入一个像ls这样的命令时,我将fork()一个新的进程,然后exec()这个ls可执行文件。 (然后我wait()子进程,但是超出了范围。)这发生在一个完全不同的地址空间,如果ls爆炸,我不在乎,因为我仍然在我自己的进程中执行。

另一方面,说我是一个数学课程,我被要求乘两个100×100矩阵。 我们知道矩阵乘法是一个令人尴尬的并行问题。 所以,我有记忆中的矩阵。 我产生了N个线程,每个线程在相同的源矩阵上运行,把它们的结果放在结果矩阵的适当位置。 请记住,这些操作是在同一个过程的背景下进行的,所以我需要确保他们没有在彼此的数据上加盖。 如果N是8,我有一个八核CPU,我可以同时有效地计算矩阵的每个部分。

使用fork()(和family)的unix进程创建机制非常有效。 更重要的是,大多数unix系统不支持内核级线程,即线程不是内核实体识别的。 因此,在这样的系统上的线程无法在内核级别获得CPU调度的好处。 pthread库做的不是可靠的,而是一些进程本身。 同样在这样的系统上,pthreads是使用vfork()来实现的,而且只是轻量级的过程。 所以使用线程是没有意义的,除了在这样的系统上的可移植性。

根据我的理解,Sun-solaris和Windows有内核级线程,而linux系列不支持内核线程。

与进程管道和unix doamin插槽是非常有效的IPC没有同步问题。 我希望它清楚为什么和什么时候线程应该用于实际。