Probleme mit fork() und mehreren Teilfenstern

X

Xayu

Grünschnabel
Hi,
Ich programmiere gerade eine Shell anwendung für Unix in C.
Folgendes Problem:
Ich habe mit der Curses Bibliothek mittels subwin() das Hauptfenster der Konsole in 4 Abschnitte unterteilt. Diese lassen sich problemlos ansprechen und mit der Funktion wprintw beschreiben. Für erleichterte parallele Ausgaben auf den Fenstern benutze ich die fork() Funktion. Leider wird die Ausgabe sobald mehr als 1 Thread läuft sehr unübersichtlich und die Texte werden nicht mehr in das eigene Fenster sondern teilweise auch in benachbarte Fenster geschrieben.

Was könnte ich falsch gemacht haben ?
Die x und y Angaben der Fenster sind 100%ig korrekt, da das Programm ohne fork() einwandfrei läuft. Auch die Indizes der verschiedenen Fenster werden korrekt verwendet, das habe ich schon überprüft. Darüberhinaus sind die Fenstervariablen statisch damit alle Prozesse auf die gleichen zugreifen. Habe auch schon versucht mit malloc() den Speicherplatz abzusichern auf dem die Variablen der Fenster liegen, aber das alles ändert nichts.

Ich weiss nicht mehr weiter.

Vielen Dank, bin für jede Hilfestellung dankbar.

MFG Xayu
 
Xayu schrieb:
[..]
und die Texte werden nicht mehr in das eigene Fenster sondern teilweise auch in benachbarte Fenster geschrieben.
[..]
Darüberhinaus sind die Fenstervariablen statisch damit alle Prozesse auf die gleichen zugreifen.
[..]
Ich kann mir grade nicht vorstellen, wie das aussieht. Schreiben die Prozesse über die Fenstergrenzen hinweg?

Dann würden nämlich grade 2 Prozesse gleichzeitig schreiben und somit aus den Grenzen hinausschreiben. Am besten benutzt du statt Prozessen Threads (fork() -> pthread_create()) und sicherst mit einem Lock (Mutex -> pthread_mutex_lock()), dass nur 1 Thread pro Fenster, oder je nach Situation, global, schreiben kann.
 
Vielen danke für den Tipp.
Ich habe nun Semaphore benutzt und alle Schreiboperationen in den Fenstern in einen kritischen Berreich gelegt, so dass jeweils nur ein Prozess gleichzeitig schreiben kann, nun sind auch die Fehler des über die Grenzen schreibens behoben. Leider ist ein Problem immer noch vorhanden, immer wenn ich mit wrefresh() ein Fenster aktualisiere verschwinden alle anderen Fenster, ich sehe immer nur eins gleichzeitig. Warum ist das so ? Wird für jeden fork() Prozess ein neuer stdscr angelegt ? und wenn ja wie kriege ich die Prozesse dazu alle in dem gleichen stdscr zu arbeiten ? Obwohl ich das nicht verstehen würde, da die 4 Fenster ja alle statisch sind und bei deren Initialisierung den stdscr des Elternprozesses übergeben bekamen.

Gruß Xayu
 
Zuletzt bearbeitet:
Wenn du verschiedene prozesse in die Windows schreiben lassen willst, würde ich stdout durch eine pipe ersetzen und ließt dann via RT Signal die Daten aus (http://www.hpl.hp.com/techreports/2000/HPL-2000-174.pdf), wenn sie ankommen und schreibst sie in's window. Das gilt natürlich auch für stdin (anderer fd der pipe) und stderr (am besten = stdin, wenn keine error handling gewünscht).
Stdscr ist (afaik), eine interne struct, die aber auch nur stdio benutzt, daher kannst du deine prozesse auch eigene windows machen lassen oder vi oder sowas in einem anderen window zu deiner status anzeige aufmachen, aber du musst noch COLUMNS und LINES auf window size setzen.
 
Zuletzt bearbeitet:
Poste mal den Code. Übrigens hat fork() nicht wirklich was mit Threads zu tun, die ich für das Problem benutzen würde...

Mfg, Lord Kefir
 
Lord Kefir schrieb:
Poste mal den Code. Übrigens hat fork() nicht wirklich was mit Threads zu tun, die ich für das Problem benutzen würde...

Mfg, Lord Kefir
Du kannst aber keine Threads bei externen Programmen benutzen, z.B. du hast jetzt das Programm mit den 2 windows, ein window zeigt vielleicht die CPU Temperature und das andere den Memory usage an, nun willst du aber z.B. tail als output für irgendwelche logs haben, da musst du (ok, man könnte auch noch irgendwie code in die Threads nachladen, aber das ist nicht gerade schön und schnell) fork benutzen. Sicherlich ist das bei diesem Beispiel nicht notwendig, da Threads benutzt werden können. Aber es geht hier um Erweiterbarkeit, wenn man sich nie mit Theorie und/oder Zukunft des Projektes kümmert, wird es auch nichts. Wenn du Code immer nur so schreibst, wie du ihn gerade brauchst und dir dann erst während der Implementierung darüber sorgen machst, wie du es implementierst, so wirst du nie ein Programm zu Ende bekommen oder ordentlich/sauber hinbekommen. Lieber vorher alle Roadmaps schmieden, viele Gedanken machen und dann nur noch sauber und erweiterungsorientiert implementieren, als diesen "Im Moment brauch ich nur das, vielleicht später mehr, aber das ist mir zu viel"-Kram.
Das ist wie in der Schule, die Leute, die ihre Aufsätze (Textproduktionen oder was auch immer) sofort hinschreiben, ohne erst zu planen und zu denken, sind entweder richtig genial oder richtig dumm, wobei das 2. warscheinlicher ist.
 
mein Code:

static WINDOW *win[4];
static int linesUp, linesDown, colsLeft, colsRight;

//Initialisierung
...
// Fenstergrößen
linesUp = LINES/2;
linesDown = LINES - linesUp; // falls ungerade
colsLeft = COLS/2;
colsRight = COLS - colsLeft;

// 4 Unterfenster
win[0] = subwin(stdscr, linesUp, colsLeft, 0, 0);
win[1] = subwin(stdscr, linesUp, colsRight, 0, colsLeft);
win[2] = subwin(stdscr, linesDown, colsLeft, linesUp, 0);
win[3] = subwin(stdscr, linesDown, colsRight, linesUp, colsLeft);
...
for(i = 0; i<4; i++){
if(fork()){
pager(fifo, i);
break;
}
}
...
void pager(int *pDatei, int winNr){
...

sb.sem_num = 8;
sb.sem_op = GRAB;
semop(semid, &sb, 1);

wclear(win[winNr]);
wprintw(win[winNr],"Fenster: %i\n\n", winNr+1);
wprintw(win[winNr],"Warte auf neuen Klienten.\n");
wrefresh(win[winNr]);

sb.sem_num = 8;
sb.sem_op = RELEASE;
semop(semid, &sb, 1);

...
}

glaube kaum dass das wieterhilft ich denke meine fragestellung war recht klar. Aber hier ist trotzdem mal der Code. Und ja ich könnte es anders machen, ich will aber wissen wie es mit fork() geht oder warum nicht.

Gruß Xayu

edit.: Achja genau und von den textausgaben in den Fenstern ist jeweils nur eine gleichzeitig sichtbar obwohl eigentlich in allen vier Fenstern "Fenster: x" stehen sollte
 
Zuletzt bearbeitet:
Sir Auron schrieb:
Du kannst aber keine Threads bei externen Programmen benutzen, z.B. du hast jetzt das Programm mit den 2 windows, ein window zeigt vielleicht die CPU Temperature und das andere den Memory usage an, nun willst du aber z.B. tail als output für irgendwelche logs haben, da musst du (ok, man könnte auch noch irgendwie code in die Threads nachladen, aber das ist nicht gerade schön und schnell) fork benutzen. Sicherlich ist das bei diesem Beispiel nicht notwendig, da Threads benutzt werden können. Aber es geht hier um Erweiterbarkeit, wenn man sich nie mit Theorie und/oder Zukunft des Projektes kümmert, wird es auch nichts. Wenn du Code immer nur so schreibst, wie du ihn gerade brauchst und dir dann erst während der Implementierung darüber sorgen machst, wie du es implementierst, so wirst du nie ein Programm zu Ende bekommen oder ordentlich/sauber hinbekommen. Lieber vorher alle Roadmaps schmieden, viele Gedanken machen und dann nur noch sauber und erweiterungsorientiert implementieren, als diesen "Im Moment brauch ich nur das, vielleicht später mehr, aber das ist mir zu viel"-Kram.
Das ist wie in der Schule, die Leute, die ihre Aufsätze (Textproduktionen oder was auch immer) sofort hinschreiben, ohne erst zu planen und zu denken, sind entweder richtig genial oder richtig dumm, wobei das 2. warscheinlicher ist.

Bei der Fülle der mir gegebenen Informationen konnte ich leider nicht erahnen, wie die Zukunft dieses "Projektes" ausschaut. Pauschal kann man sicherlich nicht behaupten, dass durch "forken" ein Programm zukünftig einfacher zu pflegen ist. Je nach Anwendungsfall gilt es selbstverständlich (wie immer), eine optimale Lösung zu finden. Generalisierung ist grundsätzlich ein Fehler.

Wenn es "nur" um die die parallele Ausgabe von Text in Pseudo-Fenstern geht, halte ich Threads für eine sehr elegante und vor allem einfachere Lösung.

Desweiteren wollte ich nur darauf Aufmerksam machen, dass es einen Unterschied zwischen Threads und fork() gibt und Xayu dazu animieren, sich darüber zu informieren, da er diesen Unterschied scheinbar nicht kennt. Dies wäre natürlich sinnvoll, wenn er eine Roadmap oder etwas ähnliches zu erstellen gedenkt.

Schau mir mal morgen in den Code rein - jetzt gehe ich erst einmal ins Bett. Es war ein langer Tag.... *gähn*

Mfg, Lord Kefir
 
Habe das ganze nun mal mit pthreads versucht aber da das gesamte Projekt unter anderem auch RPC Calls verwendet schmeisst der Compiler eine Fehlermeldung wenn ich pthreads verwende, diese sind wohl nicht kompatibel mit RPC Funktionen.

Erormessage:
cc -g -DRPC_SVC_FG -pthread -o pagerpc_client pagerpc_clnt.o pagerpc_client.o
ld: fatal: option -h and building a dynamic executable are incompatible
ld: fatal: Flags processing errors


Gruß Xayu
 
thorus schrieb:
Müsste das nicht -lpthread heissen?
Ich glaub der gcc nimmst auch so.
man gcc schrieb:
-pthread
Add support for multithreading using the POSIX threads library.
This option sets flags for both the preprocessor and linker. It
does not affect the thread safety of object code produced by the
compiler or that of libraries supplied with it. These are HP-UX
specific flags.
 
Sir Auron schrieb:
Ich glaub der gcc nimmst auch so.
Mmh, zum erstenmal gesehen. Aber eine Lektüre der Manpage zeigt auch, dass es das nur für spezielle Architekturen gibt. Für i386 und x86-64 ist das Flag nicht definiert.
Die Fehlermeldung ([..]option -h[..]) suggeriert, dass er wohl die Flags einzeln nimmt (-pthread).
 
Nun ja, habe das Problem mittlerweile in einer sehr komplizierten Funktion gelöst, die mit einem fork() realisierbar ist. Schade dass keiner wusste wie man das Problem mit mehreren fork() lösen könnte, dann hätte ich mir eine Menge arbeit gespart. Hauptsache es läuft jetzt.

Vielen Dank an alle die geholfen haben

Gruß Xayu
 
Zurück
Oben