Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » POSIX fork + scanf

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
13.05.2010, 03:53 Uhr
Giarome



Hi, ich würde mich freuen, wenn mir jemand dabei helfen könnte, dieses kleine Programm zum laufen zu bringen oder nützliche Hinweise geben könnte.

Der Fehler besteht darin, dass nach dem Timer immer die Fork PIDs ausgegeben werden und nicht auf eingabe gewartet wird -> endlos keine Eingabe möglich....

Es handelt sich um C-Code.

C++:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <curses.h>


void child(pid_t pid) {
    switch (pid) {
        case -1: {
            perror("fork failed.");
            exit(EXIT_FAILURE);
        }
        case 0: {
            printf("%d forked by %d.\n",getpid(),getppid());

            int timer = 0;
            char tea[100] = {0};

            printf("Timer> ");
/*THE FOLLOWING LINES CANNOT BE ACESSED -> INFINITE LOOP, NO POSSIBILITY TO INTERACT*/
            if (scanf("%d",&timer) < 1) {        
                printf("Input error.\n");
                exit(EXIT_FAILURE);        
            }
            printf("Tea> ");
            scanf("%99s",tea);
            
            sleep(timer);
            if (errno) {
                perror("sleep failed.");
                exit(EXIT_FAILURE);
            }
            printf("%s ready.\n",tea);
            exit(EXIT_SUCCESS);
            break;
        }
        default: {
            printf("%d forks %d.\n",getpid(),pid);
            printf("killing %d.\n",waitpid(-1,NULL,WNOHANG));
            if (errno) {
                perror("waitpid error");
                exit(EXIT_FAILURE);
            }
        }
    }
}

int main() {

    while (1) {
        child(fork());
    }

    return(EXIT_SUCCESS);

}




mfg
Giarome

Dieser Post wurde am 13.05.2010 um 03:53 Uhr von Giarome editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
13.05.2010, 04:15 Uhr
0xdeadbeef
Gott
(Operator)


Ruf waitpid nicht mit WNOHANG auf.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
13.05.2010, 13:08 Uhr
~Giarome
Gast


Das ist es nicht, lies den Kommentar.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
13.05.2010, 16:15 Uhr
0xdeadbeef
Gott
(Operator)


Das ist es, probier es aus.

So, wie es im Moment da steht, wartet der Vaterprozess nicht auf den Kindprozess und spawnt stumpf immer weiter neue Kindprozesse, die dann in scanf hängen. Jedenfalls so lange, bis fork danebengeht und errno setzt, woraufhin der Vaterprozess stirbt.

Ich rate dir dringend, die Dokumentation zu waitpid (waitpid tötet gar nichts, es sammelt nur Leichen ein) zu lesen und dich darüber zu informieren, wie man errno benutzt.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
13.05.2010, 22:04 Uhr
~Giarome
Gast


Danke für die Anregungen! Du hattest recht, dass der Vater immer neue Kindprozesse generiert, aber das lag nicht am WNOHANG. ich habe mal einen anderen Ansatz gewählt, nämlich, dass erst nach der Eingabe geforkt wird und nicht schon davor (was streng genommen auch mehr sinn macht). Hier der Code:

main.c

C++:
#include "teatimer.h"

int main() {
    child();
    return 0;
}



teatimer.h

C++:
void child();



teatimer.c

C++:
#include "teatimer.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

void collect_dead_children() {
    pid_t res;
    while((res = waitpid(-1,NULL,WNOHANG)) > 0);
    if ((res = -1))
        if (errno != ECHILD) {
            perror("waitpid");
            exit(EXIT_FAILURE);
        }
}

void child() {
    while (1) {
        int timer = 0;
        char tea[100] = {0};
        pid_t pid;

        printf("Timer> ");
         if (scanf("%d",&timer) < 1) {
             printf("Input error.\n");
             exit(EXIT_FAILURE);
        }
         printf("Tea> ");
         scanf("%99s",tea);

        collect_dead_children();
        pid = fork();
         switch (pid) {
             case -1: {
                perror("fork failed.");
                exit(EXIT_FAILURE);
            }
            case 0: {
                pid_t child = getpid();
                printf("%d forked by %d.\n",child,getppid());
                if (sleep(timer)) {
                    perror("sleep interrupted.");
                    exit(EXIT_FAILURE);
                }
                printf("%s ready.(%d)\n",tea,child);
                exit(EXIT_SUCCESS);
            }
            default: {
                printf("%d forked %d.\n",getpid(),pid);
            }
        }
    }
}



compiliert mit: gcc -Wall -ansi -pedantic main.c teatimer.c -o teatimer
alles soweit ok, Programm läuft, wie es soll. Nur jetzt habe ich das Problem, dass meine Ein-/Ausgabe in falschen Zeilen erscheint, wenn z.B. ein Prozess fertig wird, bevor ich die eingabe getätigt habe. Noch Ideen?!

mfg
R
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
13.05.2010, 22:29 Uhr
0xdeadbeef
Gott
(Operator)


Als einfachen Hack könntest du den Kindprozessen eine Zeile im Bildschirm zuweisen und mit ANSI-Escape-Sequenzen die Ausgabe darin positionieren. Etwa

C++:
printf("\x1b[s\x1b[%d;H%s ready.(%d)\n\x1b[u", row, tea, child);


Dann vor dem Forken eine freie Zeile aus beispielsweise einer Queue ziehen und in row schreiben.

Ich möchte mich allerdings nicht dafür verbürgen, wie sich das verhält, wenn zwei Prozesse gleichzeitig beenden (ich bin nicht sicher, ob \x1b[s und \x1b[u einen Stack bedienen). Um sicher zu sein, müsstest du die Prozesse untereinander synchronisieren, so dass immer nur einer zur Zeit etwas ausgibt, etwa mit einem Semaphor.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
13.05.2010, 23:08 Uhr
~Giarome
Gast


Danke, danke! Vielen Dank! Das wird jetzt etwas tricky....
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
15.05.2010, 00:01 Uhr
0xdeadbeef
Gott
(Operator)


Überhaupt...gibt es einen Grund, warum du das mit Prozessen machst? Es ist so zwar möglich, aber mit Threads wäre es eigentlich einfacher.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
15.05.2010, 17:47 Uhr
~Giarome
Gast


Ich bin noch nicht so weit und habe von Threads kein großes Verständnis. Das ist zum lernen gedacht. Wie würde mans denn machen?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: