如果我有一个进程,并且我克隆它,那么PID是否相同?

时间:2011-02-01 11:35:31

标签: linux exec fork pid

只是一个简单的问题,如果我克隆一个进程,克隆进程的PID是一样的,是吗? fork()创建一个PID不同的子进程,但其他一切都是相同的。 Vfork()使用相同的PID创建子进程。 Exec可以将当前正在执行的进程更改为其他进程。

我在所有这些陈述中都是正确的吗?

5 个答案:

答案 0 :(得分:6)

不完全。如果您通过fork / exec或vfork / exec克隆进程,您将获得一个新的进程ID。 fork()将为您提供具有新进程ID的新进程,exec()将使用新进程替换该进程,但保留进程ID。

来自here

  

vfork()函数不同于   fork()只在那个子进程中   可以与。分享代码和数据   调用进程(父进程)。这个   加快克隆活动的速度   存在风险的完整性   如果vfork()被滥用,则为父进程。

答案 1 :(得分:6)

虽然fork() 可以在一个场景(* a)中,但vfork()clone()都不会保持相同的PID。它们是实现大致相同目的的不同方式,即创建 distinct 子项。

clone()fork()类似,但两个进程共享许多内容,这通常用于启用线程。

vfork()clone的变体,其中父项将暂停,直到子进程退出或执行另一个程序。在这些情况下它更有效,因为它不涉及复制页表等。基本上,只要孩子加载另一个程序,一切都在两个进程之间共享。

将最后一个选项与正常的写时复制进行对比,其中共享内存本身(直到其中一个进程写入它),但复制了引用该内存的页表。换句话说,vfork()甚至比写时复制更多更高效,至少对于fork-follow-immediate-exec用例。

但是,在大多数案例中,子项与父项具有不同的进程ID。


* a clone() CLONE_THREAD时,事情变得棘手。在那个阶段,进程仍然具有不同的标识符,但是PID的构成开始变得模糊。在最深层次上,Linux调度程序不关心进程,它会调度线程。

线程具有线程ID(TID)和线程组ID(TGID)。 TGID是您从getpid()获得的。

当一个线程克隆而没有 CLONE_THREAD时,它会被赋予一个新的TID,并且它的TGID也设置为该值(即一个全新的PID)。

使用 CLONE_THREAD,它会获得一个新的TID,但TGID(因此报告的进程ID)保持与父级相同,因此它们实际上具有相同的PID。但是,他们可以通过从gettid()获取TID来区分自己。

关于父进程ID和信号传递(包括组内线程和SIGCHLD到父级)都有相当多的诡计,所有这些都可以从{ {3}}

答案 2 :(得分:3)

值得一些解释。雨很简单。

考虑一下。程序必须同时做一些事情。比如,你的程序正在打印“你好世界!”,每一秒,直到有人进入“你好,迈克”,然后,每一秒,它打印出那个字符串,等待约翰在将来改变它。

你怎么用标准的方式写这个?在您的程序中,基本上打印“hello”,您必须创建另一个等待用户输入的分支。

您创建两个进程,一个输出这些字符串,另一个等待用户输入。并且,在UNIX中创建新进程的 only 方法是调用系统调用fork(),如下所示:

ret = fork();
if(ret > 0) /* parent, continue waiting */
else /* child */

这个方案带来了许多问题。用户输入“Mike”但您没有简单的方法将该字符串传递给父进程,以便能够打印它,因为+每个+进程都有自己的内存视图,不与子进程共享。

当fork()创建进程时,每个进程都会收到内存现有副本,如果该内存确实发生了变化< / em>之后,那些内存段相同的映射将立即被分析(它被称为写时复制机制)。

在子和父之间共享的另一个好处是,例如,打开的文件描述符,共享内存的描述符,输入/输出内容等,在fork()之后也无法生存。

因此。 fork()调用已经得到缓解,包括共享内存/信号等。但是如何?这就是clone()背后的想法。该电话会显示一个标记,表示您与孩子分享的内容。例如,内存,信号处理程序等。如果你用flag = 0调用它,它将与fork()相同,直到它们所采用的args。当创建POSIX pthreads时,该标志将反映您在pthread_attr中指示的属性。

从内核的角度来看,创建这种方式的进程之间没有区别,也没有特殊的语义来区分“processess”。内核甚至不知道,“线程”是什么,它创建了一个新的进程,但它只是将它与那些拥有父级的进程组相提并论。叫它,注意那个过程可能会做什么。因此,您在进程组中有不同的进程(共享相同的pid),每个进程分配有不同的“TID”(从父进程的PID开始)。 注意解释clone()就是这样做的。你可以传递你需要的 whaterver (事实上,旧的vfork()调用会这样做)。你要分享记忆吗? Hanlers?你可以调整所有内容,只要确保你不会在这个调用周围立即写入pthreads库。 重要的是,内核版本非常复杂,它只需要传递4个参数中的2个,用户堆栈和选项。

答案 3 :(得分:1)

由于PID是进程的唯一标识符,因此无法使用相同的PID进行两个不同的进程。

答案 4 :(得分:0)

线程(具有相同的可见“pid”)通过clone()调用实现。当提供标志CLONE_THREAD时,新进程('线程')与其创建者进程共享线程组标识符(TGID)。 getpid实际上返回了TGID。

有关详细信息,请参阅clone manpage

总之,内核看到的真实PID总是不同的。线程的可见PID是相同的。