如果我有一个过程,我克隆它,PID是一样的吗?

只是一个简单的问题,如果我克隆一个进程,克隆进程的PID是一样的,是吗? fork()在PID不同的地方创build一个subprocess,但是其他的都是一样的。 Vfork()创build一个具有相同PID的subprocess。 Exec可以将当前正在执行的进程更改为其他内容。

我在所有这些陈述中是否正确?

不完全的。 如果您通过fork / exec或vfork / exec克隆进程,您将获得一个新的进程ID。 fork()会给你一个新的进程ID, exec()用新的进程替换进程,但是维护进程ID。

从这里 :

vfork()函数与fork()的不同之处在于,子进程可以与调用进程(父进程)共享代码和数据。 如果vfork()被滥用,这会显着加速克隆活动对父进程完整性的风险。

虽然clone() 可以在一个场景(* a)中,但是fork()vfork()保持相同的PID。 他们都是以不同的方式达到大致相同的目的,创造一个独特的孩子。

clone()就像fork()但是这两个进程共享了很多东西,这通常用于启用线程。

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

将最后一个选项与内存本身共享的正常写入时复制(直到其中一个进程写入)之间进行对比,而将引用该内存的页表复制。 换句话说, vfork()比copy-on-write 更有效率,至少对fork-followed-by-immediate-exec用例来说是这样的。

但是,在大多数情况下,这个孩子与父母有不同的进程ID。


* 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传递给父进程),有相当多的诡计正在进行,所有这些都可以从clone()手册页中查看 。

这值得一些解释。 就像下雨一样简单

考虑一下。 一个程序必须同时做一些事情。 假设你的程序正在打印“hello world!”,每秒钟,直到有人输入“hello,Mike”,然后每秒打印一下这个字符串,等待John将来改变这个。

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

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

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

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

当fork()创建进程时,每个进程都会收到当前存在的内存的一个副本 ,如果这个内存真的在后面改变 ,那么这些内存段的映射就会一次被修改(它被称为副本在写机制)。

例如,在孩子和父母之间共享的另外一些东西是打开文件描述符,共享内存的描述符,输入/输出内容等等,这些在fork()之后也不会存在。

所以。 fork()调用必须得到缓解,包括共享内存/信号等,但是如何呢? 这是clone()背后的想法。 这个电话会带上一个标志,表明会和孩子分享什么 。 例如,内存,信号处理程序等。如果你用flag = 0来调用它,这将和fork() 相同 ,直到它们所用的参数。 当POSIX pthread创建时,该标志将反映您在pthread_attr中指定的属性。

从内核的角度来看,用这种方式创建的进程没有区别,也没有特殊的语义来区分“进程”。 内核甚至不知道这个“线程”是什么,它创建一个新的进程,但是它简单地把它合并到那个有父进程调用它的进程组中,注意那个进程可能做什么。 所以,你有不同的程序(共享相同的PID)在一个进程组合每个分配一个不同的“TID”(从父的PID开始)。 小心解释克隆()就是这样做的。 你可能会通过这个whaterver你需要(事实上,旧的vfork()电话会做)。 你打算分享内存吗? Hanlers? 你可以调整一切,只要确保你不与在这个电话中写的pthreads库冲突。 一个重要的事情,内核vesion是相当无耻的,它只能传递4个参数中的2个,用户堆栈和选项。

由于PID是一个进程的唯一标识符,所以没有办法使用相同的PID有两个不同的进程。

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

有关更多详细信息,请参阅克隆手册页 。

总之,内核所见的真实PID总是不同的。 可见的PID对于线程是相同的。