【问题标题】:Does fork() create aliases?fork() 会创建别名吗?
【发布时间】:2017-01-27 19:03:53
【问题描述】:

当我使用fork() 创建子进程时,子进程是父进程的副本。指针会在每个进程中指向相同的事物,还是指针在子进程中采用新值。数组或文件指针呢?

【问题讨论】:

  • 子节点中的指针与父节点中的指针拥有相同的地址。它指向的地址在子节点和父节点中都保存着相同的数据。如果其中一个进程写入该值,则在该进程中将有所不同,但在另一个中则不同。如果一个进程从 FILE * 读取,它的 FILE * 的内部副本会被更新(例如,它在文件中的位置),但不会在另一个进程中。但是,在两个进程中都可以看到任何修改底层文件描述符的内容。
  • 那么指针指向同一个值,但是同一个值的两个不同副本?这就是我很好奇的地方,当我阅读您的评论时,这就是您所说的?
  • 指针具有相同的值,并且在每个进程返回fork()的瞬间它们指向的相同的。之后会发生什么取决于每个进程:它们的地址空间是不同的。
  • @EJP 所以我认为我的问题来自对地址空间的误解。那么是相对于地址空间的指针吗?就像在fork之后的两个指针一样,指向重复地址空间内相对相同的空间?我理解对了吗?

标签: c linux operating-system fork


【解决方案1】:

指针会在每个进程中指向相同的东西吗?

是的,所有内存都被复制了,包括指针。

数组或文件指针呢?

是的。对于文件 descriptors,需要注意的是,在父进程中打开的任何文件描述符都将引用子进程中的相同文件。


大多数(全部?)Unix 系统使用某种形式的写时复制优化,这意味着进程实际上将共享物理内存,直到它们中的任何一个写入内存。这往往使 fork() 成为一个非常便宜的操作。

正如 Vazquez-Abrams 所指出的那样,存在一些极端情况。也许最重要的一点是只派生了一个线程,即调用 fork() 系统调用的线程。

【讨论】:

    【解决方案2】:

    来自fork(2) man page(强调我的):

    新进程,称为子进程,是调用进程(称为父进程)的完全相同除了以下几点:: p>

    * 子进程有自己唯一的进程 ID,并且这个 PID 不匹配任何现有进程组的 ID (setpgid(2))。

    * 子进程的父进程 ID 与父进程 ID 相同。

    * 子进程不会继承其父进程的内存锁(mlock(2)、mlockall(2))。

    * 进程资源利用率 (getrusage(2)) 和 CPU 时间计数器 (times(2)) 在子进程中重置为零。

    * 孩子的待处理信号集最初是空的(sigpending(2))。

    * 子进程不会从其父进程 (semop(2)) 继承信号量调整。

    * 子进程不会从其父进程 (fcntl(2)) 继承记录锁。

    * 子进程不会从其父进程继承计时器(setitimer(2)、alarm(2)、timer_create(2))。

    * 子进程不会从其父进程(aio_read(3)、aio_write(3))继承未完成的异步 I/O 操作,也不会从其父进程继承任何异步 I/O 上下文(请参阅 io_setup(2))。

    上述列表中的进程属性均在 POSIX.1-2001 中指定。父子进程在以下 Linux 特定进程属性方面也有所不同:

    * 子进程不会从其父进程继承目录更改通知 (dnotify)(参见 fcntl(2) 中对 F_NOTIFY 的描述)。

    * prctl(2) PR_SET_PDEATHSIG 设置被重置,以便子级在其父级终止时不会收到信号。

    * 默认计时器松弛值设置为父级的当前计时器松弛值。请参阅 prctl(2) 中对 PR_SET_TIMERSLACK 的描述。

    * 使用 madvise(2) MADV_DONTFORK 标志标记的内存映射不会通过 fork() 继承。

    * 子进程的终止信号始终是 SIGCHLD(参见 clone(2))。

    * ioperm(2) 设置的端口访问权限位不被孩子继承;孩子必须使用 ioperm(2) 打开它需要的任何位。

    请注意以下几点:

    * 子进程是用一个线程创建的——即调用 fork() 的线程。父级的整个虚拟地址空间在子级中复制,包括互斥锁、条件变量和其他 pthread 对象的状态;使用 pthread_atfork(3) 可能有助于处理这可能导致的问题。

    * 子继承父的一组打开文件描述符的副本。子文件中的每个文件描述符与父文件中的相应文件描述符引用相同的打开文件描述(请参阅 open(2))。这意味着两个描述符共享打开文件状态标志、当前文件偏移量和信号驱动的 I/O 属性(参见 fcntl(2) 中对 F_SETOWN 和 F_SETSIG 的描述)。

    * 子进程继承父进程的一组开放消息队列描述符的副本(参见 mq_overview(7))。子项中的每个描述符都与父项中的相应描述符引用相同的打开消息队列描述。这意味着两个描述符共享相同的标志 (mq_flags)。

    * 子进程继承父进程的一组开放目录流的副本(参见 opendir(3))。 POSIX.1-2001表示父子中对应的目录流可以共享目录流定位;在 Linux/glibc 上他们没有。

    【讨论】:

    • 我直接去了手册页,但它有点难以解读。
    • "子级继承父级打开文件描述符集的副本。子级中的每个文件描述符引用与父级相应文件描述符相同的打开文件描述(参见 open(2)) . 这意味着两个描述符共享打开文件状态标志、当前文件偏移量和信号驱动的 I/O 属性(参见 fcntl(2) 中 F_SETOWN 和 F_SETSIG 的描述)。”
    猜你喜欢
    • 1970-01-01
    • 2012-08-02
    • 1970-01-01
    • 2014-06-21
    • 2023-04-10
    • 2020-01-26
    • 2014-07-20
    • 2015-03-01
    • 1970-01-01
    相关资源
    最近更新 更多