Hallo,
ich verzweifle an einem Problem mit select().
Ich nutze select() um abzufragen ob Kommandos in stdin warten, die ich
dann zeilenweise einlese und abarbeite. Das ganze funktioniert auch ganz
gut solange nur ein Kommando wartet.
Warten mehrere Kommandos in stdin (also auch mehrere Zeilen) passiert
folgendes:
- select() wird aufgerufen, gibt 1 zurück --> Kommandos warten
- die erste Zeile wird eingelesen und verarbeitet
- erneuter select()-Aufruf um auf weitere Kommandos zu prüfen
- select() gibt 0 (also keine weiteren Kommandos) zurück
Wenn ich stdin zeichenweise einlese liefert select() solange 1 bis ein
Zeilenumbruch gelesen wird.
Hier nochmal ein Minimalbeispiel:
1
tv.tv_sec=2;
2
tv.tv_usec=0;
3
FD_ZERO(&fds);
4
FD_SET(STDIN_FILENO,&fds);
5
ret=select(STDIN_FILENO+1,&fds,NULL,NULL,&tv);// gibt 1 zurück
6
fgets(buffer,1024,stdin);
7
8
tv.tv_sec=2;
9
tv.tv_usec=0;
10
FD_ZERO(&fds);
11
FD_SET(STDIN_FILENO,&fds);
12
ret=select(STDIN_FILENO+1,&fds,NULL,NULL,&tv);// gibt 0 zurück, auch wenn noch zeilen in stdin warten
13
14
fgets(buffer,1024,stdin);// <-- liefert nicht blockierend nächste Zeile
Ich würde ja alle Zeilen in stdin einfach auslesen und puffern, aber wie
soll ich rauskriegen wieviele Zeilen in stdin warten um kein
blockierendes fgets() aufzurufen.
Das ganz passiert unter Red Hat Linux 4.1.2-46 (Kernel
2.6.18_164.11.1.e15)
Schonmal vielen Dank für eure Hilfe!
select und die stdio-Funktionen lassen sich nicht gut mischen, da
fgets&Co einen eigenen Buffer-Layer mitbringen, über dessen Zustand
"select" nichts weiß.
=> Wenn select, dann "read" statt fgets
Außerdem kehrt select mit zurück, wenn Daten verfügbar sind. Das muß
aber nicht zwingend eine ganze Zeile sein. fgets() wartet aber, bis eine
komplette Zeile da ist.
Fritz schrieb:> Ich würde ja alle Zeilen in stdin einfach auslesen und puffern, aber wie> soll ich rauskriegen wieviele Zeilen in stdin warten um kein> blockierendes fgets() aufzurufen.
Nomalerweise läuft es nicht so, daß die gesamte Eingabe schon im Puffer
wartet und man die dann komplett auf einmal einliest, sondern du
wartest, bis die Daten, die du erwartest, angekommen sind.
Εrnst B✶ schrieb:> select und die stdio-Funktionen lassen sich nicht gut mischen, da> fgets&Co einen eigenen Buffer-Layer mitbringen, über dessen Zustand> "select" nichts weiß.
Das mit dem eigenen Buffer bei fgets()&Co habe ich nicht gewusst. read()
löst das Problem. Vielen Dank!
Rolf Magnus schrieb:> Außerdem kehrt select mit zurück, wenn Daten verfügbar sind. Das muß> aber nicht zwingend eine ganze Zeile sein. fgets() wartet aber, bis eine> komplette Zeile da ist.
Da die Standardeingabe zeilengepuffert ist, kommen die Daten dort immer
zeilenweise an. Oder irre ich mich da?
Fritz schrieb:> Da die Standardeingabe zeilengepuffert ist, kommen die Daten dort immer> zeilenweise an.
Kann man so nicht sagen. "Zeilenweises Lesen" ist eine Eigenschaft der
Funktion fgets(). "Puffern" ist eine Eigenschaft der C-Library (standard
input/output library functions). select() und read() sind Systemaufrufe
und passen zwar zueinander, aber eben nicht so ohne weiteres zu fgets()
usw.
Für Unix/Linux hängt das Puffern auch vom Datei-Typ ab. Für reguläre
Dateien ist die Standard-Puffergröße gerne sowas wie 8192 Byte ("block
buffered" oder "fully buffered"), zumindest aber passend zur Blockgröße
des Dateisystems. Für sowas wie Terminals oder Sockets macht das wenig
Sinn. Hier wird "line buffered" verwendet, wenn es denn zeilenorientiert
zugeht oder schließlich "unbuffered", also zeichenorientiert. Siehe auch
"man setbuf".
Im beschriebenen Fall könnte man ganz auf select() verzichten und nur
mit fgets() arbeiten, wenn man das Einlesen in einen eigenen Thread
packt. Da gibt es dann eben andere Fallstricke...