【问题标题】:Linux CreateProcess?Linux 创建进程?
【发布时间】:2011-08-18 12:21:04
【问题描述】:

我在 Linux 平台上开发。

我想在我的库中创建一个新进程而不替换当前正在执行的图像。

因为我正在开发一个库,所以我没有 main 函数。

并且我想在调用程序应用程序关闭后继续新进程(就像CreateProcess Windows API)。

在 Linux 中是否可行?

类似这样的功能:

void Linux_CreateProcess(const char* app_name)
{
  // Executing app_name.

  // ???????? what is the code ??????

  // app_name is running and never close if current application close.
  return;
}

注意:

  • system() 阻塞当前进程,不好。我想继续当前的进程。

  • exec()family 替换当前执行的镜像,不好。

  • popen() 如果当前进程关闭,则关闭新进程。

【问题讨论】:

    标签: c++ c linux createprocess


    【解决方案1】:

    我认为fork 是您正在寻找的。​​p>

    【讨论】:

      【解决方案2】:

      posix_spawn 可能是目前首选的解决方案。

      在此之前fork() 然后execXX() 是执行此操作的方法(其中execXXexec 系列函数之一,包括execlexeclpexecle、@987654330 @、execvpexecvpe)。目前在 GNU C 库中,至少对于 Linux,posix_spawn 无论如何都是通过 fork/exec 实现的; Linux 没有posix_spawn 系统调用。

      您将使用fork()(或vfork())启动一个单独的进程,该进程将是父进程的克隆。在子进程和父进程中,执行都会继续,但fork 在任何一种情况下都会返回不同的值,以便您进行区分。然后,您可以在子进程中使用execXX() 函数之一。

      但是请注意,这个问题 - 文字来自我的一篇博文 (http://davmac.wordpress.com/2008/11/25/forkexec-is-forked-up/):

      似乎没有任何简单的符合标准的方法(甚至一般可移植的方法)来并行执行另一个进程并确保 exec() 调用成功。问题是,一旦你 fork()d 然后成功 exec()d 你就不能与父进程通信来通知 exec() 成功了。如果 exec() 失败,那么您可以与父级通信(例如通过信号),但您无法通知成功 - 父级可以确保 exec() 成功的唯一方法是等待子级要完成的过程(并检查是否没有失败指示),这当然不是并行执行。

      即如果execXX() 成功,您将不再拥有控制权,因此无法向原始(父)进程发出成功信号。

      此问题的潜在解决方案,以防您遇到问题:

      [...] 使用 pipe() 创建管道,将输出端设置为 close-on-exec,然后 fork()(或 vfork()),exec(),然后写一些东西(可能是 errno ) 如果 exec() 失败(在调用 _exit() 之前)到管道。父进程可以从管道中读取数据,如果 exec() 成功,将立即获得输入结束,如果 exec() 失败,则将获得一些数据。

      (请注意,如果子进程以低于父进程的优先级运行,并且父进程等待它的输出,则此解决方案很容易导致优先级反转。

      上面和其他答案中也有posix_spawn,但它不能解决检测执行子可执行文件失败的问题,因为它通常是按照 fork/exec 实现的,并且可以返回成功在exec() 阶段失败之前。

      【讨论】:

      • 但我无法访问 main() 函数,我开发了一个库。
      • 没关系。当你 fork() 从你调用 fork() 的点开始在子进程中继续执行 - 它不会在 main() 中重新启动。
      • 哦,我认为 fork 会导致从 main 重新启动应用程序 :) 谢谢
      【解决方案3】:

      您应该使用fork(),然后使用execvp()

      fork() 函数创建一个新的子进程。在父进程中,您会收到子进程的进程 ID。在子进程中,返回的进程 ID 为 0,这告诉我们该进程是子进程。

      execvp() 用新的进程映像替换调用进程映像。这具有使用调用进程的进程 ID 运行新程序的效果。注意没有启动一个新进程;新的过程映像只是简单地覆盖了原始过程映像。 execvp 函数最常用于覆盖通过调用 fork 函数创建的进程映像。

      【讨论】:

        【解决方案4】:

        执行此操作的经典方法是使用 fork() 创建一个子进程,然后使用其中一个 exec() 函数替换子进程的执行映像,而使父进程保持不变。然后这两个进程将并行运行。

        【讨论】:

          【解决方案5】:

          是的,fork() 和 exec..() 是正确的解决方案。看看这段代码是否对你有帮助:

          switch( fork() )
          {
              case -1 : // Error
                      // Handle the error
                      break;
          
              case 0 :
                      // Call one of the exec -- personally I prefer execlp
                      execlp("path/to/binary","binary name", arg1, arg2, .., NULL);
          
                      exit(42); // May never be returned
                      break;
          
              default :
          
                      // Do what you want
                      break;  
          }
          

          【讨论】:

            【解决方案6】:

            fork/exec 组合已经提到过,但还有posix_spawn 系列函数可以用来替代fork + exec,更直接地等同于@ 987654327@。以下是两种可能性的示例:

            #include <stdlib.h>
            #include <stdio.h>
            #include <string.h>
            
            #include <unistd.h>
            #include <spawn.h>
            #include <sys/wait.h>
            
            extern char **environ;
            
            void test_fork_exec(void);
            void test_posix_spawn(void);
            
            int main(void) {
              test_fork_exec();
              test_posix_spawn();
              return EXIT_SUCCESS;
            }
            
            void test_fork_exec(void) {
              pid_t pid;
              int status;
              puts("Testing fork/exec");
              fflush(NULL);
              pid = fork();
              switch (pid) {
              case -1:
                perror("fork");
                break;
              case 0:
                execl("/bin/ls", "ls", (char *) 0);
                perror("exec");
                break;
              default:
                printf("Child id: %i\n", pid);
                fflush(NULL);
                if (waitpid(pid, &status, 0) != -1) {
                  printf("Child exited with status %i\n", status);
                } else {
                  perror("waitpid");
                }
                break;
              }
            }
            
            void test_posix_spawn(void) {
              pid_t pid;
              char *argv[] = {"ls", (char *) 0};
              int status;
              puts("Testing posix_spawn");
              fflush(NULL);
              status = posix_spawn(&pid, "/bin/ls", NULL, NULL, argv, environ);
              if (status == 0) {
                printf("Child id: %i\n", pid);
                fflush(NULL);
                if (waitpid(pid, &status, 0) != -1) {
                  printf("Child exited with status %i\n", status);
                } else {
                  perror("waitpid");
                }
              } else {
                printf("posix_spawn: %s\n", strerror(status));
              }
            }
            

            【讨论】:

            • posix_spawn() 似乎即使可执行路径不存在也返回 0(成功),这不是很有帮助。
            【解决方案7】:

            我认为 posix_spawn 可以满足您的需求。在内部,它可能会执行 fork/exec,但也可能会做一些时髦有用的事情。

            【讨论】:

            • 我不知道 - 它解决了我在 fork/exec 组合中发现的一些问题。
            【解决方案8】:

            你写道:

            我想在我的库中创建一个新进程而不替换当前正在执行的图像。 system() 阻塞当前进程,不好。我想继续当前进程。

            只需在命令调用后添加一个 & 符号。 示例:system("/bin/my_prog_name &amp;");

            你的进程不会被阻塞!

            【讨论】:

              猜你喜欢
              • 2017-10-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-07-31
              • 2015-07-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多