【问题标题】:Linux equivalent of Process.Start()Linux 等价于 Process.Start()
【发布时间】:2020-07-28 05:43:31
【问题描述】:

在 C# 中的 Windows 上,我可以通过调用 Process.Start() 从我的代码中启动一个外部程序,它会启动进程并返回其 ID。这很重要,因为我没有分叉我自己的进程,而且我以后可能不得不终止该进程。

我查看了exec()fork() 和许多其他在 C++ 中的 Linux 下的东西,但没有一个做完全相同的事情。例如,system() 在程序运行时阻塞,fork() 复制我的整个进程,以便我可以运行另一个任务。

谁能告诉我等价物是什么?

【问题讨论】:

标签: c++ linux process


【解决方案1】:

在 Linux 上启动新进程的方法是使用 forkexec。您可以将其包装在您自己的 System 类中,该类包含 PID 并提供终止进程等的方法。此类的一个示例是 Qt 库中的 QProcess

【讨论】:

  • 感谢您的快速回复。为了运行“解压缩”命令,我真的必须分叉,创建整个多媒体应用程序的副本吗?
  • @DerfSkren:不幸的是,有几十年的软件绝对依赖于此,所以是的。
  • @DerfSkren Re.复制整个应用程序,情况并没有你想象的那么糟糕。见this post
  • 另请注意,还有 vfork,它会在执行新内容之前创建进程的副本。
  • @Botje 无论如何都是“写时复制”,因此对于直接进入exec 的分叉进程,内核中根本不会发生太多实际复制。
【解决方案2】:

没有等价物。这是 Windows 和 Linux(以及任何其他类 Unix 系统)之间的区别。在类 Unix 系统中,新进程总是使用fork() + exec() 启动。 system() 等更高级别的 C 库 API 在后台使用 fork() + exec() 系统调用,因为绝对没有其他方法。但 Windows 总是从头开始创建新进程。但是您不应因fork() 创建当前进程的副本而气馁。事实上,它以一种非常具体的方式进行操作,因此实际上在写入内存之前几乎没有复制任何内容。即使在这种情况下,也只会复制修改后的内存页面。否则,在 Unix/Linux 上创建新进程将过于昂贵(例如,假设一个消耗 4GB 内存的进程想要执行一些 shell 命令)。事实上,exec() 完成了 CreateProcess() 在 Windows 上所做的工作 - 分配新的可执行映像来处理,重新初始化堆和堆栈。

【讨论】:

  • 感谢更详细的解释。最后我可能不得不使用 fork,但上面关于 posix_spawn() 的评论是我在寻找什么。
  • 根据手册页,实际上是 fork()execve() 组合的包装,所以基本上你仍然在使用它们,也许以更方便的方式。
  • 是的,从我读到的内容来看,它是为了提供更好的界面而创建的,但还包括一些安全性和内务管理,可以在不像现代 Linux 发行版那样分叉的 Posix 环境中更好地工作。
【解决方案3】:

感谢@user4581301 的上述评论。 posix_spawn() 是我要找的。​​p>

这是我最终使用的代码。

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

class ProcessCancelHelper {
 private:
  pid_t process_id_;

 public:
  ProcessCancelHelper()
  : process_id_(0) {}

  int StartProcess(const char* command_buffer) {
    const char* command_argv[4];
    command_argv[0] = "sh";
    command_argv[1] = "-c";
    command_argv[2] = command_buffer;
    command_argv[3] = nullptr;

    process_id_ = fork();
    if (process_id_ == -1) return -1;
    if (process_id_ == 0) {
      execvp(command_argv[0], const_cast<char* const*>(command_argv));
      assert(false && "execvp did not work");
      exit(-1);
    }

    int wait_status;
    if (waitpid(process_id_, &wait_status, 0))
    {
      process_id_ = 0;
      if (WIFEXITED(wait_status)) return (WEXITSTATUS(wait_status));
      return -1;
    }

    process_id_ = 0;
    return -1;
  }

  bool CancelProcess() {
    return (process_id_ != 0 && kill(process_id_, SIGKILL) == 0);
  }
}

这可行,我还没有尝试改用posix_spawn,但正如所讨论的那样,这只是一个包装器。

【讨论】:

    猜你喜欢
    • 2013-09-08
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 2023-04-11
    • 2014-04-14
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多