Запуск асинхронных процессов с использованием C в * nix - PullRequest
0 голосов
/ 02 апреля 2012

У меня есть такая ситуация:

start();
<Some code>
end();

Я хочу, чтобы функция start() запускала процесс (не отдельные потоки), который делает что-то асинхронно (то есть, я имею в виду сразу после запуска процесса,элемент управления должен вернуться к родительскому элементу, а порожденный процесс переходит в фоновый режим с родительским процессом, а затем после завершения блока <Some code> функция end() будет kill идентификатор процесса, связанный с start().Я не уверен, как это сделать, особенно в части, чтобы сделать блоки родительского и дочернего кода асинхронными;нужна помощь.Благодарю.

РЕДАКТИРОВАТЬ: После получения помощи от членов, я смог написать этот код, но это имеет проблемы, было бы здорово, если бы кто-то мог указать на ошибки.Все, что я хочу для _do_(), - это инициировать дочерний процесс, который никогда не завершится, если _stop_() не сможет его убить.Но по какой-то причине родительский процесс теряется, и программа бесконечно работает в цикле * 1013.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

pid_t id = 0;

int _do_()
{
//int status;
pid_t childpid; /* variable to store the child's pid */
FILE *fp= NULL;
childpid = fork();

//child stuff
if (childpid == 0) 
{
    id = getpid();
    fp = fopen ("Log.txt", "w+");
    while (1)
    {
        fprintf(fp, "Logging info...\n");
        fflush(fp);
    }
    fclose(fp);
}

if (childpid < 0) /* fork returns -1 on failure */
{
    perror("fork"); /* display error message */
    exit(-1); 
}

 return 0;

}

 //kill child process in _do_()
 int _stop_()
 {
  int en;
  printf("Going to kill child ID: %d\n", id);
  if (kill ( id , SIGKILL ) < 0)
  {
    en = errno;
    printf("Error while trying to KILL process: %s\n", strerror(en));
  }
  printf("Logging ended\n");

    return 0;

 }

 int main(int argc, char* argv[])
 {
   int i;

   _do_();
   for (i = 0; i < 200; i++)
    ;
   _stop_();
   printf("\nEnded...\n");
   return 0;
}

EDIT2: я не мог сделать то, что хотел, убив процесс, запущенный в start()с end() вместо этого запустил процесс демона и позволил ему сбрасывать значения в файл до тех пор, пока размер файла не достигнет некоторого заранее заданного предела.Это самое близкое к тому, что я хотел.

Ответы [ 2 ]

4 голосов
/ 02 апреля 2012

Вы хотите найти примеры того, как работает fork / exec / kill.

обычно вы форкаете процесс, который создает два процесса: дочерний и родительский.Дочерний возвращается из «fork» с кодом возврата 0. Родительский процесс возвращает pid child - вот как вы узнаете, являетесь ли вы дочерним или родительским.

Теперь, если вы хотите выполнить какую-то другую программу,может вызвать 'exec' из дочернего процесса.Однако у вас может быть такой код:

pid = fork();
if (pid == 0)
{
  // do child stuff here
  exit (0);
}
if (pid == -1)
 // failed to fork, deal with it

// parent code goes here
...
...
kill(pid, SIGKILL); // you can kill your child process here if you want to.
                    // thanks to Adam Rosenfield for pointing out the signal number has to be sent

Это просто, если вы посмотрите учебник по нему.Windows работает по-другому, поэтому, если вы хотите перенести свой код в windows, используйте как fork, так и exec, поскольку windows фактически не создает идентичную копию программы - она ​​фактически всегда порождает новую программу.

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

edit: перед выполнением 'kill (pid, SIGKILL)' вы действительно хотите сделатьуверен, что ваш ребенок еще жив.Если ваш ребенок умер, pid мог бы быть повторно использован другим процессом, и в этом случае вы можете завершить какой-то случайный процесс.

edit2: в вашем коде есть ошибка.

1 - remove 'int id...'
2 - move pid_t childpid; from function into global scope
3 - kill childpid, not 'id'
1 голос
/ 02 апреля 2012

В разделе «// do child stuff here» вы можете выполнить второй раз и завершить процесс original-child, позволяя внуку продолжить работу, но теперь он наследуется программой init (идентификатор процесса 1).Примерно так:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

void OutputPids(const char *tag)
{
    printf("in %s process %d, parent is %d\n", tag, getpid(), getppid());
}

int main(int ac, char **av)
{
    pid_t pid_child = -1;
    OutputPids("original");
    if(-1 == (pid_child = fork())) {
        perror("fork (for child)");
    } else if(0 == pid_child) {     /* fleeting child process */
        pid_t pid_grandchild = -1;
        if(-1 == (pid_grandchild = fork())) {
            perror("fork (for granchchild)");
        } else if(0 == pid_grandchild) { /* in grandchild */
            int i;
            setsid();
            setpgid(0, 0);
            for(i = sysconf(_SC_OPEN_MAX) ; i > 3 ; --i)
                close(i);  // close any stray filedescriptors
            OutputPids("grandchild(ready)");
            // run the rest of the command line as a asynch command
            execvp(av[1], av + 1);
            perror("execvp");
            exit(1);
        }
        OutputPids("child(suiciding)");
        _exit(0);           /* skip atexit processing, etc. */
    } else  {                   /* original process */
        OutputPids("original(waiting)");
        wait(pid_child);                /* wait for child to die (quick) */
    }
    OutputPids("original(after fork)");
    // stuff for your main routine continues here...
    sleep(2);
    OutputPids("original(done)");
    return 0;
}

Пример выполнения:

$ ./doublefork echo GRANDCHILD OUTPUT
in original process 13414, parent is 22338
in original(waiting) process 13414, parent is 22338
in child(suiciding) process 13415, parent is 13414
in original(after fork) process 13414, parent is 22338
in grandchild(ready) process 13416, parent is 1
GRANDCHILD OUTPUT
in original(done) process 13414, parent is 22338
$
...