【问题标题】:Why does Unix have fork() but not CreateProcess()?为什么 Unix 有 fork() 而没有 CreateProcess()?
【发布时间】:2011-10-15 19:42:27
【问题描述】:

我不明白为什么 Unix 有 fork() 来创建一个新进程。在 Win32 API 中,我们有CreateProcess(),它创建一个新进程并将可执行文件加载到其地址空间,然后从入口点开始执行。但是 Unix 提供了 fork 来创建一个新进程,我不明白如果我想运行另一个进程,我为什么要复制我的进程。

所以让我问这两个问题:

  1. 如果fork() 然后exec() 更高效,为什么没有函数forkexec(const char *newProc),因为我们几乎在所有情况下都会在fork() 之后调用exec()
  2. 如果不是更高效,为什么fork() 存在呢?

【问题讨论】:

    标签: winapi unix exec fork createprocess


    【解决方案1】:

    fork() 调用就足够了。它也更灵活;它允许您调整子进程中的 I/O 重定向等操作,而不是使创建进程的系统调用复杂化。使用 SUID 或 SGID 程序,它允许子进程在执行其他进程之前失去其提升的权限。

    如果您想要一种复杂的方式来创建进程,请查找posix_spawn() 函数。

    #include <spawn.h>
    
    int posix_spawn(pid_t *restrict pid, const char *restrict path,
            const posix_spawn_file_actions_t *file_actions,
            const posix_spawnattr_t *restrict attrp,
            char *const argv[restrict], char *const envp[restrict]);
    
    int posix_spawnp(pid_t *restrict pid, const char *restrict file,
              const posix_spawn_file_actions_t *file_actions,
           const posix_spawnattr_t *restrict attrp,
           char *const argv[restrict], char *const envp[restrict]);
    

    不同之处在于 posix_spawnp() 在 PATH 上搜索可执行文件。

    还有一整套用于处理posix_spawn_file_actions_tposix_spawnattr_t 类型的其他函数(按照参考手册页底部的“另见”链接)。

    这有点像 Windows 上的CreateProcess()。不过,在大多数情况下,使用fork() 后跟exec() 更简单。


    我不明白你的意思。子进程代码由我来写,那么写if (fork() == 0)和把这段代码放在child的main()开头有什么区别?

    很多时候,你执行的代码不是你写的,所以你不能修改子进程开始时发生的事情。想想贝壳;如果你从 shell 中运行的程序只有你自己写的那些,那你的生活将会非常贫困。

    很多时候,您执行的代码会从许多不同的地方调用。特别是,考虑一个 shell 和一个程序,它们有时会在管道中执行,有时会在没有管道的情况下执行。被调用的程序不能告诉它应该做什么 I/O 重定向和修复;调用程序知道。

    如果调用程序以提升的权限(SUID 或 SGID 权限)运行,则通常希望在运行另一个程序之前关闭这些权限。依靠其他程序知道该做什么是……愚蠢的。

    【讨论】:

    • 我不明白你的意思。子进程代码将由我编写,那么编写 if (fork() == 0) 和将此代码放在子进程的 main() 开头有什么区别?
    • hmm,所以你说使用 fork() - exec() 夫妇更容易做这样的事情(i/o 重定向,收回权限等)我是否正确?
    • 是的:与posix_spawn() 所需的扭曲相比,使用fork() 然后让孩子在使用exec() 之前执行它需要的动作要简单得多。阅读posix_spawn() 的理由;它很有启发性(或者,至少对我来说是这样)。您可以使用 posix_spawn() 执行的操作列表令人印象深刻,但它也比 fork() 提供的更复杂。
    【解决方案2】:

    类 UNIX 操作系统(至少是较新的 Linux 和 BSD 内核)通常有一个非常高效fork 实现——它“非常便宜”以至于有基于“线程”的实现它在某些语言中。

    最后,forkexec 函数是 ~n -- 对于一些小的 n -- 行应用程序代码。

    我真希望 windows 有这么有用的ForkProcess :(

    编码愉快。


    提到了一个 cnicutar,Copy-On-Write (COW) 是使用的一种策略。

    【讨论】:

    • 好的,但是如果我将在非常有效的分叉之后将流程转换为另一个流程,那么从一开始就创建新流程不是更好吗?然后我不必重复我自己的过程。这是我没有得到的
    • @Ali Veli 现代分叉根本不重复这个过程。查找“写入时复制”。
    • @Ali Veli “没关系”。听听高德纳。
    • @pst,我将其解释为您没有答案
    • @L.B 否。将它们分开的原因(以及组合方法)已在其他地方得到解答。我的回应是解决“没关系”的问题。为什么要引入一个新的调用来做一些不需要做的事情?您是否想让所有符合标准的操作系统(对于所述标准,调用将成为其中的一部分)必须实现所述调用?它将如何影响外观的可移植性?这是一个合理的决定吗?那我的回答。无需为不存在的问题发明解决方案。
    【解决方案3】:

    有一个函数相当于forkexec - system

    http://www.tutorialspoint.com/c_standard_library/c_function_system.htm

    #include <stdio.h>
    #include <string.h>
    
    int main ()
    {
      char command[50];
    
      strcpy( command, "ls -l" );
      system(command);
    
      return(0);
    } 
    

    【讨论】:

    • system(3) 将你给它的命令传递给 shell。虽然它通常在 fork(2)/execve(2) 之上实现,但它们并不相同。
    猜你喜欢
    • 2015-02-12
    • 1970-01-01
    • 2016-02-06
    • 2016-06-28
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    相关资源
    最近更新 更多