Linux CreateProcess?

Разрабатываю на платформе Linux.

Я хочу создать новый процесс в своей библиотеке, не заменяя текущий исполняемый образ.

Поскольку я разрабатываю библиотеку, у меня нет основной функции.

И я хочу продолжить новый процесс после закрытия приложения-вызова (так же, как 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() заменяют текущий исполняемый образ, это нехорошо.

  • popen() закрывает новый процесс, если текущий процесс закрыт.


person Amir Saniyan    schedule 04.05.2011    source источник


Ответы (8)


posix_spawn, вероятно, является предпочтительным решением в наши дни.

До этого для этого использовался fork(), а затем execXX() (где execXX — одна из функций семейства exec, включая execl, execlp, execle, execv, execvp и execvpe). В настоящее время в библиотеке 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(), вы не можете связаться с родительским процессом, чтобы сообщить об успешном выполнении exec(). Если exec() терпит неудачу, вы можете общаться с родителем (например, через сигнал), но вы не можете сообщить об успехе - единственный способ, которым родитель может быть уверен в успехе exec(), - это ждать() для ребенка процесс для завершения (и убедитесь, что нет индикации сбоя) и, конечно же, это не параллельное выполнение.

то есть, если execXX() завершается успешно, вы больше не имеете контроля, поэтому не можете сигнализировать об успехе исходному (родительскому) процессу.

Возможное решение этой проблемы, если это проблема в вашем случае:

[...] используйте pipe() для создания канала, установите конец вывода как close-on-exec, затем fork() (или vfork()), exec() и напишите что-нибудь (возможно, errno) в pipe в случае сбоя exec() (до вызова _exit()). Родительский процесс может читать из канала и получит немедленный конец ввода, если exec() завершится успешно, или некоторые данные, если exec() завершится ошибкой.

(Обратите внимание, что это решение может вызвать инверсию приоритета, если дочерний процесс выполняется с более низким приоритетом, чем родительский, и родительский процесс ожидает выходных данных от него).

Существует также posix_spawn, как упоминалось выше и в других ответах, но он не решает проблему обнаружения сбоя при выполнении дочернего исполняемого файла, поскольку он в любом случае часто реализуется с точки зрения fork/exec и может вернуть успех до сбоя этапа exec() .

person davmac    schedule 04.05.2011
comment
но у меня нет доступа к функции main(), я разрабатываю библиотеку. - person Amir Saniyan; 04.05.2011
comment
Это не имеет значения. Когда вы выполняете fork(), выполнение продолжается в дочернем элементе с точки, которую вы вызвали fork(), и не перезапускается в main(). - person davmac; 04.05.2011
comment
О, я думал, что форк вызовет перезапуск приложения из основного :) Спасибо - person Amir Saniyan; 04.05.2011

Комбинация fork/exec уже упоминалась, но есть также семейство функций 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));
  }
}
person Philipp    schedule 04.05.2011
comment
posix_spawn(), кажется, возвращает 0 (успех), даже если путь к исполняемому файлу не существует, что не очень полезно. - person Étienne; 19.08.2016

Вы написали:

Я хочу создать новый процесс в своей библиотеке, не заменяя текущий исполняемый образ. system() блокирует текущий процесс, это нехорошо. Я хочу продолжить текущий процесс.

Просто добавьте амперсанд после вызова команды. Пример: system("/bin/my_prog_name &");

Ваш процесс не будет заблокирован!

person Ivan    schedule 06.05.2014

Классический способ сделать это — использовать fork() для создания дочернего процесса, а затем использовать одну из функций exec() для замены исполняемого образа дочернего процесса, оставив родительский процесс нетронутым. Оба процесса будут работать параллельно.

person Community    schedule 04.05.2011

Я думаю, что posix_spawn делает то, что вы хотите. Внутри он может выполнять fork/exec, но, возможно, он также делает некоторые полезные вещи.

person MarkR    schedule 04.05.2011
comment
Я не знал об этом - это решает некоторые проблемы, которые я определил с комбинацией fork/exec. - person davmac; 07.05.2011

Вы должны использовать fork(), а затем execvp().

Функция fork() создает новый дочерний процесс. В родительском процессе вы получаете идентификатор дочернего процесса. В дочернем процессе возвращаемый идентификатор процесса равен 0, что говорит нам о том, что процесс является дочерним процессом.

execvp() заменяет образ вызывающего процесса новым образом процесса. Это приводит к запуску новой программы с идентификатором вызывающего процесса. Обратите внимание, что новый процесс не запускается; новый образ процесса просто накладывается на исходный образ процесса. Функция execvp чаще всего используется для наложения образа процесса, созданного вызовом функции fork.

person Alok Save    schedule 04.05.2011

Да, 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;  
}
person Olwaro    schedule 04.05.2011

Я думаю, что fork это то, что вы ищете.

person Daniel A. White    schedule 04.05.2011