C und fork() -- Wie vom Parent zum Client reden?

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
MrScoville
Beiträge: 93
Registriert: 09.09.2016 17:20:59
Lizenz eigener Beiträge: MIT Lizenz

C und fork() -- Wie vom Parent zum Client reden?

Beitrag von MrScoville » 07.11.2016 21:18:44

Hallo,

folgendes kleines Problemchen hätte ich heute anzubieten... Also, ich schreibe gerade ein kleines Programm in C (eigentlich in C++, bitte also nicht gleich über die Syntax wundern, ich oller C# Addict, ich...)

Das Programm soll einfach ein Child abforken, aber der Parent soll dem Client noch etwas mitgeben können.

So sieht der Code aus:

Code: Alles auswählen

int main(int argc, string* argv)
{
    static volatile int ppid = -1;

    volatile int pid = fork();
    
    if (pid > 0) // Parent
    {
        try
        {
            ppid = pid;
        }
        catch (const exception& e)
        {
            cout << e.what() << "\n";
        }
        
        cout << "PID: " << pid << "\n"; // (1)
    }
    else if (pid == 0) // Child
    {
        try
        {
            while (ppid == -1)
            {
                usleep(1000);
            }
        }
        catch (const exception& e)
        {
            cout << e.what() << "\n";
        }
        
        for (int i = 0; i < 10; i++) // (2)
        {
            cout << "Child: " << i << "\n";
            usleep(100000);
        }
    }
    else // Error
    {
        cout << "Error creating the child.\n";
        return -1;
    }
    
    return 0;
}
Das ganze try-catch-Gedöns habe ich zum Testen eingebaut, weil: Ich benutze Netbeans und gdb und bash, und alle finden den Code prima und beschweren sich nicht.

So, was der Code tut, ist, die PID ausgeben in der mit (1) markierten Zeile und dann auszusteigen.
Wenn ich alles, was mit der Variablen ppid zu tun hat, auskommentiere, läuft aber plötzlich der Code ab (2).

Und so soll es ja auch sein: Ein Thread für den Parent, weitere für die Children. Nun sollte man davon ausgehen können, dass der Parent-Prozess zuerst abläuft, und in den Children ist eben extra die while-Schleife eingebaut, die so lange warten soll, bis ppid sich von -1 auf einan andere Wert ändert.

So, dass das alles nicht sauber ist, sehe ich selbst. Ich bin aber mit den Feinheiten von fork() nicht so vertraut wie vielleicht einige von euch mit denen von C#. Da würde man das eh ganz anders machen mit async, await und vllt sogar Events.

Was ich an meinem Code eigentlich nicht verstehe, ist folgendes: Okay, der Parent setzt ppid auf pid und steigt dann aus. Währenddessen läuft fork() durch und erzeugt das Child. Da ich ppid als static volatile definiert habe, würde ich erwarten, dass der Compiler sich mit Optimierungen zurück hält und static wörtlich nimmt. In der while-Schleife warte ich, bis sich ppid von -1 auf einan anderen Wert ändert. Wenn nun der komplette Code der Funktion in den fork() geworfen wird, dürfte die while-Schleife ja nie enden, und das Programm sollte hängen. Tut es aber nicht, es steigt einfach aus nach der Ausgabe der PID.

Any help appreciated!
Man mag gar nicht glauben, wie sehr ein 4096-bittiger RSA-Schlüssel einem den Tag vermiesen kann...^^

Der so genannte "Teufel im Detail" hat einen Namen: Tight coupling :evil:

Benutzeravatar
chabayo
Beiträge: 930
Registriert: 17.08.2005 07:44:33
Kontaktdaten:

Re: C und fork() -- Wie vom Parent zum Client reden?

Beitrag von chabayo » 08.11.2016 10:45:28

Hallo, ich bin kein Meister des Durchblicks in C und POSIX-Prozessen, zmnd. glaube ich das dies das Leitthema des Threads :roll: ist.

Das was du schriebst ist kein C, wohl eher C++, oder?

Dein Problem scheint zu sein das der Parent endet, und damit dein Child auch. Das kann man aendern, hab gerade keinen Zugriff auf meine Beispiele von damals als ich damit spielte, darum keine genauere Hilfe. Im Grunde macht man das wenn man einen Daemon programmiert, und die Eingabeaufforderung an den Aufrufenden Prozess zurueckgibt. Schau also mal auf die Manualpage von setsid(), ich erinner mich wage diese Funktion im Child aufzurufen.

Wenn du beide Prozesse erhalten tust und sie kommunizieren lassen willst, macht man das mit pipe(), das in seiner Manpage auch ein Beispiel dazu hat.
Watt about the non-digital!?

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C und fork() -- Wie vom Parent zum Client reden?

Beitrag von wanne » 08.11.2016 13:56:00

Mit fork() erzeugst du einen neuen Prozess.
Ziehe dazu:
https://de.wikipedia.org/wiki/Prozess_% ... esskontext
https://de.wikipedia.org/wiki/Virtuelle ... verwaltung

Kommunizieren kannst du über pipes, Shared Memory oder über Dateien.
Alternativ wäre Multithreading, wie du das von C# kennst. (Das hat aber nichts mit verschiedenen Prozessen zu tun.)
rot: Moderator wanne spricht, default: User wanne spricht.

Benutzeravatar
schorsch_76
Beiträge: 2543
Registriert: 06.11.2007 16:00:42
Lizenz eigener Beiträge: MIT Lizenz

Re: C und fork() -- Wie vom Parent zum Client reden?

Beitrag von schorsch_76 » 10.11.2016 08:26:11

Bei einem fork() [1] wird der komplette Speicher kopiert (COW). Du kannst dem child also im Speicher eine Variable übergeben ;). Nach dem fork haben beide Prozesse getrennte Addressräume. Kontinuierliche Kommunikation geht über IPC Mechanismen wie pipes, named pipes, message queues, shared memory (man mmap) ....

Der Parent sollte auf das Kind warten. wait() [2]. Wenn der Parent stirbt, wird init der parent des Kindes und macht den wait.

Hier ein Miniprogramm.
http://www.csl.mtu.edu/cs4411.ck/www/NO ... reate.html

Falls du das wirklich wissen willst, kann ich dir das Buch empfehlen:
The Linux Programming Interface: A Linux and UNIX System Programming Handbook
Gibt's auch als ebook.

[1] https://linux.die.net/man/2/fork
[2] https://linux.die.net/man/2/wait

MrScoville
Beiträge: 93
Registriert: 09.09.2016 17:20:59
Lizenz eigener Beiträge: MIT Lizenz

Re: C und fork() -- Wie vom Parent zum Client reden?

Beitrag von MrScoville » 10.11.2016 18:20:22

Oh okay okay okay... Dass ich wenig Ahnung von der Sache habe, wusste ich schon vorher... Dass es SO wenig ist, ist ja schon peinlich...

Danke für die Geduld erst einmal. Jetzt stelle ich mich mal so ahnungslos wie ich bin und frage: Wie machen Apache und Co. denn das? Also Eltern-Prozess lauscht auf einen Port, bekommt einen connect, tut vllt. etwas damit und erzeugt dann einen neuen Prozess(?) / Thread(?), der den Request dann bearbeitet. Oder auch: vor Urzeiten (Slackwaresaurus) hatte ich mal ein Tool installiert, das Festplatten defragmentierte, auch DOS-Partitionen. Das ging so vor, dass ein Eltern-Prozess über die Konsole gestartet wurde, der pro physischer Platte einen Kind-Prozess startete, der im Hintergrund lief, sodass der Eltern-Prozess sich beendete, die Defragmentierung trotzdem weiter rödelte. Das Spannende an dem Tool war, dass man nun über die Konsole das Tool noch einmal aufrufen konnte (neue PID, klar), und es zeigte an, was die Kind-Prozesse denn gerade trieben. Also ich nenne die mal "Kind-Prozesse", möglich, dass es einfach unabhängige Prozesse waren, die irgendwie über IPC kommunizierten.
Man mag gar nicht glauben, wie sehr ein 4096-bittiger RSA-Schlüssel einem den Tag vermiesen kann...^^

Der so genannte "Teufel im Detail" hat einen Namen: Tight coupling :evil:

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C und fork() -- Wie vom Parent zum Client reden?

Beitrag von wanne » 11.11.2016 00:48:12

MrScoville hat geschrieben:Jetzt stelle ich mich mal so ahnungslos wie ich bin und frage: Wie machen Apache und Co. denn das?
Das willst du lieber nicht wissen. Webserver sind extrem auf Performance bei nebenläufigkeit optimiert. Da werden dann ganz gerne viele Tricks genutzt, die du garantiert nicht machen willst. (Beispielsweise haben viel Webserver sogar eigene leichtgewichtigere "Threads" mit Kooperatives Multitasking und ähnlichem.)
MrScoville hat geschrieben:Das ging so vor, dass ein Eltern-Prozess über die Konsole gestartet wurde, der pro physischer Platte einen Kind-Prozess startete, der im Hintergrund lief, sodass der Eltern-Prozess sich beendete, die Defragmentierung trotzdem weiter rödelte.
Typischerweise macht man das mit dem doublefork. Der eigentliche neue Prozess läuft als "Enkel", der Kindprozess kann dann beendet werden, weil das Terminal noch da ist.
ALternativen sind ein fork() beim beenden des Parent oder daemon().
MrScoville hat geschrieben:Das Spannende an dem Tool war, dass man nun über die Konsole das Tool noch einmal aufrufen konnte (neue PID, klar), und es zeigte an, was die Kind-Prozesse denn gerade trieben. Also ich nenne die mal "Kind-Prozesse", möglich, dass es einfach unabhängige Prozesse waren, die irgendwie über IPC kommunizierten.
Das klingt ganz stark nach Files. Der Hintergrundprozess schreibt Daten in eine Datei, die der Vordergrundproszess dann ausließt. Eine Methode, die praktisch überall funktioniert und vor allem bis in die 90er Jahre DIE Form von IPC waren. (Abgesehen von Argumenten beim Aufrufen des Prozesses. In 99% ist das ausreichend, weil man nur einmal von Parent zu Child kommunizieren will.)
Später ist man typischerweise auf IP umgestiegen (Einfach eine Verbindung nach 127.0.0.1 und du kannst mit dir selber reden.)

Heute sind andere Methoden beliebter, weil diese deutlich performanter sind. Alle mit verschiedenen vor und Nachteilen. IPC ist so ziemlich eines der komplexesten Felder der Informatik.

Wie schon gesagt: UNIX-Sockets, Pipes, Shared Memory, Signals, MPI…

Ich glaube aber dass DU ganz sicher nicht mit mehreren Prozessen arbeiten willst.
Sag mal was dein Problem ist.
rot: Moderator wanne spricht, default: User wanne spricht.

Antworten