2012-04-01 7 views
0

ich eine Situation wie diese haben:Starten asynchrone Prozesse unter Verwendung von C in * nix

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

Ich möchte start() Funktion einen Prozess (nicht separate Threads) zu starten, die etwas asynchron tut (durch, dass ich sofort nach dem Laichen bedeuten der Prozess, das Steuerelement sollte zurück zum übergeordneten und der erzeugte Prozess in 'Hintergrund') mit dem übergeordneten Prozess, und dann nach <Some code> Block endet, end() Funktion wäre kill die Prozess-ID mit start() verbunden. Ich bin nicht sicher, wie dies zu tun ist, vor allem der Teil, um Eltern- und Kind-Code-Blöcke asynchron zu machen; Hilfe benötigen. Vielen Dank.

EDIT: Nachdem ich Hilfe von den Mitgliedern bekommen habe, konnte ich diesen Code schreiben, aber das hat Probleme, es wäre toll, wenn jemand auf die Fehler hinweisen könnte. Alles, was ich für _do_() will ist, einen Kindprozess zu initiieren, der nie enden könnte, wenn _stop_() es nicht töten kann. Aber aus irgendeinem Grund geht der Elternprozess verloren und das Programm läuft unbegrenzt auf der while() Schleife.

#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: Ich konnte nicht das tun, was ich wollte, ein Prozess, bei start() von end() begann zu töten, anstatt einen Daemon-Prozess gestartet und lassen Sie es Werte Dump auf eine Datei, bis die Dateigröße bis zu einem gewissen vorgegebenen Grenzwert erreicht . Dies ist das nächste, was ich wollte.

+0

Welches Betriebssystem? –

+0

Siehe [diese SO-Frage] (http://stackoverflow.com/q/7794273/960195) - es enthält den Code, um 'start' zu implementieren, und es fragt nach dem Code für' end'. –

+0

Linux-Systeme ... – Sayan

Antwort

4

Sie möchten einige Beispiele dazu finden, wie fork/exec/kill funktioniert.

Normalerweise verzweigen Sie einen Prozess, der zwei Prozesse erstellt: ein Kind und ein Elternteil. Das Kind gibt von "fork" mit dem Rückgabecode 0 zurück. Der Elternprozess gibt pid of child zurück - so wissen Sie, ob Sie ein Kind oder ein Elternteil sind.

Wenn Sie jetzt ein anderes Programm ausführen möchten, können Sie 'exec' vom Kindprozess aufrufen. Sie könnten jedoch auch Code wie:

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 

Es ist einfach, wenn Sie sich ein Tutorial auf es betrachten. Windows funktioniert anders, wenn Sie also Ihren Code in Windows portieren wollen, verwenden Sie sowohl fork als auch exec, da Windows nicht wirklich eine identische Kopie des Programms erstellt - es erzeugt tatsächlich immer ein neues Programm.

Ich glaube, zitieren Sie mich nicht, als Windows-Programmierer neigen dazu, Threads mehr als Unix-Programmierer zu verwenden - wie die Erstellung eines neuen Prozesses auf Windows ist eine große Sache. Auf Unix ist es nicht so groß, aber es ist größer als ein Thread. Aber Thread-Programmierung ist so viel schwieriger, im Vergleich, Sie wollen wahrscheinlich davon wegbleiben, es sei denn, Sie wirklich wirklich brauchen.

bearbeiten: bevor Sie 'kill (pid, SIGKILL)' tun, möchten Sie wirklich sicherstellen, dass Ihr Kind noch am Leben ist. Wenn Ihr Kind gestorben ist, könnte das Pid durch einen anderen Prozess wiederverwendet worden sein. In diesem Fall können Sie einen zufälligen Prozess beenden.

edit2: Es gibt einen Fehler in Ihrem Code.

1 - remove 'int id...' 
2 - move pid_t childpid; from function into global scope 
3 - kill childpid, not 'id' 
+0

Danke, vor allem für die Bearbeitung und eine nette Zusammenfassung – Sayan

+1

+1, aber um pedantisch zu sein, ist es 'kill (pid, SIG)' (nicht 'kill (pid)'), wobei 'SIG' der Name des Signals ist du willst senden, wahrscheinlich 'SIGKILL' in diesem Fall. –

+0

Ich habe ein Problem, in Start() habe ich zwei Abschnitte, einen für Kind ein anderer für Eltern, ich bin aus dem Elternteil, aber nicht aus dem Kind. Später, bei 'end()' gebe ich ein 'kill (pid, SIGKILL)' aus, wobei pid eine globale Variable ist, damit ich die pid des Kindes bekomme. Aber irgendwie ist das Kind noch am Leben ... – Sayan

1

Im „// Kind tun Sachen hier“ Abschnitt, könnte man ein zweites Mal Gabel und töten die Original-Kind-Prozess, lassen die Enkel weitergehen, aber jetzt durch das Programm init (Prozess-ID 1) geerbt .Etwas wie folgt aus:

#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; 
} 

Beispiel laufen:

$ ./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 
$ 
Verwandte Themen