12

我在Linux平台上开发。

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

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

我想在调用程序应用程序关闭后继续新进程(就像CreateProcessWindows 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()如果当前进程关闭,则关闭新进程。

4

8 回答 8

40

/组合已经提到过forkexec但是还有posix_spawn一系列函数可以用来替代fork+exec并且更直接地等同于CreateProcess. 这是两种可能性的示例:

#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));
  }
}
于 2011-05-04T13:59:24.290 回答
15

posix_spawn这些天可能是首选的解决方案。

在此之前,fork()然后execXX()是执行此操作的方法(其中execXX一个exec函数族,包括execlexeclpexecleexecvexecvpexecvpe)。目前在 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()阶段失败之前返回成功。

于 2011-05-04T12:39:22.853 回答
4

你写了:

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

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

你的进程不会被阻塞!

于 2014-05-06T19:57:07.710 回答
2

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

于 2011-05-04T12:40:45.733 回答
2

我认为 posix_spawn 做你想要的。在内部它可能会执行 fork/exec,但也可能会做一些时髦有用的东西。

于 2011-05-04T15:11:35.757 回答
1

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

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

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

于 2011-05-04T12:40:20.220 回答
1

是的,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;  
}
于 2011-05-04T13:03:10.147 回答
-1

我想fork这就是你要找的。

于 2011-05-04T12:38:52.513 回答