Linux CreateProcess? - PullRequest
       8

Linux CreateProcess?

9 голосов
/ 04 мая 2011

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

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

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

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

Ответы [ 8 ]

36 голосов
/ 04 мая 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));
  }
}
15 голосов
/ 04 мая 2011

fork(), а затем exec() является стандартным решением.

Используйте fork() (или vfork()) для запуска отдельного процесса, который будет клоном родительского.И в дочернем, и в родительском процессе выполнение продолжается, но fork возвращает другое значение в любом случае, позволяя вам различать.Затем вы можете использовать exec() из дочернего процесса.

Заметьте, однако, из одной из моих публикаций в блоге (http://davmac.wordpress.com/2008/11/25/forkexec-is-forked-up/):

Кажется, что нетлюбой простой, совместимый со стандартами способ (или даже вообще переносимый способ) параллельно выполнять другой процесс и быть уверенным, что вызов exec () был успешным. Проблема в том, что после того, как вы выполните fork () d, а затем успешно выполните exec ()Если вы не можете связаться с родительским процессом, чтобы сообщить, что exec () был успешным. Если exec () не работает, то вы можете связаться с родителем (через сигнал, например), но вы не можете сообщить об успехе -Единственный способ, которым родитель может быть уверен в успехе exec (), - это дождаться () завершения дочернего процесса (и проверить, что нет индикации сбоев), и это, конечно, не параллельное выполнение.

Потенциальное решение этой проблемы, в случае, если это проблема в вашем случае:

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

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

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

4 голосов
/ 06 мая 2014

Вы писали:

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

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

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

3 голосов
/ 04 мая 2011

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

2 голосов
/ 04 мая 2011

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

2 голосов
/ 04 мая 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;  
}
2 голосов
/ 04 мая 2011

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

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

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

0 голосов
/ 04 мая 2011

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

...