Process-Streams


#1

Hi!

Wollte nur noch mal sicher gehen, daß das, was ich vorhabe, auch wirklich nicht in Java funktioniert.

Ich möchte gerne eine Art grafische Konsole/Terminal haben, das in Java geschrieben ist.
Dafür eignet sich eigentlich dieses hier
Process p = Runtime.getRuntime().exec("java TestPrints");

Die Zeile führt dann somit das Java-Programm TestPrints aus gibt die Ausgaben des Programms an den Process p.

Ein

int data = input.read();
while (data != -1) {
 char cdata;
 cdata = (char) data;
 System.out.print(cdata);
 data = input.read();
}
input.close();

gibt dann auch aus, was es von dem Programm “TestPrints” empfangen hat.

Nun gibt es aber direkt drei Streams von Process. Und genau das ist das Problem.

Obiges funktioniert nur für die Standardausgabe. Die Fehlerausgabe, liest man mit dem ErrorStream ein:

int data = error.read();
 while (data != -1) {
 char cdata;
 cdata = (char) data;
 System.out.print(cdata);
 data = error.read();
}
error.close();

Angenommen das auszuführende Programm TestPrints.java sieht folgendermaßen aus (zu beachten, daß ich manchmal System.out,println() und manchmal System.err,println() geschrieben habe):

  public static void main(String[] args) {
    System.out.println("normal");
    System.err.println("error");
    System.out.println("wieder normal");
    System.err.println("wieder error");
    System.out.println("eins");
    System.out.println("zwei");
    System.out.println("dreimal normal");
    System.err.println("1");
    System.err.println("2");
    System.err.println("3");
    System.err.println("4 x error");
    System.out.println("und wieder normal");
    System.out.print("Dieses ");
    System.err.print("ist ");
    System.out.print("nun ");
    System.out.print("ein ");
    System.out.print("ge");
    System.err.print("mischter ");
    System.err.println("Text");
    System.out.print("Mal sehen,");
    System.err.print(" ob ");
    System.err.print("es");
    System.out.println(" funktioniert");
  }
}

Dann wird es in einer normalen Konsole/Terminal alles nacheinander genau so ausgegeben.
Bei Process habe ich jedoch zwei verschiedene Streams, die jeweils irgendwann ankommen und sich nicht an die ursprüngliche Reihenfolge halten.

Noch schlimmer wird es, wenn man den OutputStream hinzunimmt. Angenommen das aufgerufene Programm TestPrints.java sieht so aus


public class TestPrints {
  public static void main(String[] args) {
    System.out.print("Wie heißt Du? ");
    Scanner scan = new Scanner(System.in);
    String s = scan.nextLine();
    System.out.println("Hallo " + s + ", schoen Dich getroffen zu haben.");
  }
}

Dann kann es sein, daß die Tastatureingabe-Abfrage vor der Frage erscheint, auf die man antworten soll.

Grüße
theuserbl

*** Edit ***

Nachtrag: Obiges, daß sie Reihenfolge willkürlich ist, bezieht sich darauf, wenn ich die drei Streams in drei verschiedenen Threads laufen lasse.

Wenn alle im selben Thread sind, dann gebe ich mal die komplette Standardausgabe aus, dann die Fehlerausgabe und dann kommt die komplette Tastaturabfrage.
Letztendlich ist das dann genauso schlecht.

Das Problem bleiben halt die drei unabhängigen Streams.

Grüße
theuserbl


#2

dass normale Ausgabe und Error-Ausgabe durcheinandergeraten ist ein Grundproblem,
welches ich etwa ständig in Eclipse-Entwicklungsumgebung sehe,

so hilfreich die rote Schrift auch ist, schlecht wenn sie 10 Zeilen früher oder später erscheint als zugehörige sonstige Debug-Ausgaben,

könnte man mit bisschen Aufwand, neue System.out + System.err setzen, wahrscheinlich korrigieren,
zumindest die automatischen Ausgaben an beide Streams auf System.out kontrolliert umleiten,
oder mit größeren Pausen bei Wechsel System.out + System.err getrennt zulassen

der Empfänger solcher Streams kann wirklich kaum was machen wenn alles zeitgleich, richtig, hmm

deine Sorge ist dabei dass ein Thread lange unterbrochen wird?
ich glaube das sind höchstens ms, kaum der Rede wert außer es geht wirklich um Reihenfolge sprudelnder Ausgaben wie bei Eclipse-Konsole


das mit der Eingabe habe ich nicht recht verstanden, was hat das speziell mit Process zu tun?
auch in jedem normalen Programm oder am Telefon mit Behörde Xy kann man schneller antworten als die Frage kommt


#3

Danke erst nochmal, daß Du so schnell geantwortet hast.

[QUOTE=SlaterB]könnte man mit bisschen Aufwand, neue System.out + System.err setzen, wahrscheinlich korrigieren,
zumindest die automatischen Ausgaben an beide Streams auf System.out kontrolliert umleiten,
oder mit größeren Pausen bei Wechsel System.out + System.err getrennt zulassen[/quote]Möglich, daß das helfen könnte. Aber das Hauptproblem sind ja nicht System.out.println() und System.err.println(). Denn beide werden in einer normalen Konsole ja in der richtigen Reihenfolge abgearbeitet. Das Problem ist nun mal java.lang.Process und seine getInputStream(), getErrorStream() und getOutputStream Methoden. An der Stelle müßte etwas geändert werden.

deine Sorge ist dabei dass ein Thread lange unterbrochen wird?
Nein. Mir ging es einfach nur darum, daß ich von Java aus, die empfangenen Rückmeldungen eines Programms, auch in der Reihenfolge wiedergegeben bekomme, wie es das Programm abgesendet hat.

das mit der Eingabe habe ich nicht recht verstanden, was hat das speziell mit Process zu tun?
auch in jedem normalen Programm oder am Telefon mit Behörde Xy kann man schneller antworten als die Frage kommt

Das ist, weil ich letztens bei einem Programm gewissermaßen keine Frage bekam und sie gewissermaßen erst kam, als ich die Antwort eingegeben hatte. Habe somit das Gefühl, daß der OutputStream, wenn er eine Tastatureingabe erwartet, die beiden anderen Streams solange unterdrückt.

Grüße
theuserbl


#4

[QUOTE=theuserbl] Aber das Hauptproblem sind ja nicht System.out.println() und System.err.println(). Denn beide werden in einer normalen Konsole ja in der richtigen Reihenfolge abgearbeitet.
[/quote]
äh, nein, sie geraten durcheinander, also bei mir jedenfalls,
teils weil das Senden nicht genau genug passiert, teils vielleicht weil die Konsole beim Empfang genau das gleiche Problem hat,
aber eher Spekulation als Wahrheit

da du das Senden nicht beeinflussen kannst ist dieser Absatz von mir aber in der Tat weitgehend egal,

zum Empfang habe ich wohl nicht mehr als schon geschrieben

Das ist, weil ich letztens bei einem Programm gewissermaßen keine Frage bekam und sie gewissermaßen erst kam, als ich die Antwort eingegeben hatte. Habe somit das Gefühl, daß der OutputStream, wenn er eine Tastatureingabe erwartet, die beiden anderen Streams solange unterdrückt.

Standardweisheit: bei Gefühl sollte es nicht bleiben, sondern genau prüfen,
eine solche Verzögerung wäre natürlich ein Fehler,

aber das kann sich ja nur auf konkreten Code, sowohl deine Process-Behandlung als auch vielleicht das andere Programm, beziehen,
nur zum Code könnte man Fehler suchen

die gepostete TestPrints-Klasse ist ja die normale, da gibts nicht viel zu zu sagen,
wenn du aber noch ein Process-Code dazu hast, der exakt mit diesem Code das Fehlverhalten hat,
dann kann man evtl. nochmal genauer schauen


#5

[QUOTE=SlaterB]äh, nein, sie geraten durcheinander, also bei mir jedenfalls,
teils weil das Senden nicht genau genug passiert, teils vielleicht weil die Konsole beim Empfang genau das gleiche Problem hat,
aber eher Spekulation als Wahrheit[/quote]Also bei mir sind sie sowohl unter Windows, als auch unter Linux, bisher immer in der richtigen Reihenfolge gewesen.

die gepostete TestPrints-Klasse ist ja die normale, da gibts nicht viel zu zu sagen,
wenn du aber noch ein Process-Code dazu hast, der exakt mit diesem Code das Fehlverhalten hat,
dann kann man evtl. nochmal genauer schauen

Naja, Code jetzt nicht unbedingt. Hatte unter
http://fifesoft.com/projects.php
RText runtergeladen. Und dort gibt es in der dort eigenen Konsole genau das Problem:
http://fifesoft.com/forum/viewtopic.php?f=5&t=875
Bin noch nicht einmal sicher, ob er eine Tastaturabfrage überhaupt abfragt. Aber sie macht Probleme und gibt nicht die Frage aus, zu der sie die Antwort erwartet. Der ganze Text den man zuvor ausgegeben hatte, wird aber angezeigt (wobei Standardausgabe und Errorausgabe halt auch nicht in der richtigen Reihenfolge sind). Und wenn man den Prozeß beendet, indem man auf den roten Knopf dort drückt, erscheint plötzlich die Frage.

Grüße
theuserbl


#6

Also die Standard-PrintStreams “out” und “err” sind grundsätzlich nur ein Stream und wenn man in Java in einem Thread in “out” und in einem anderen in “err” schreibt, kann die Reihenfolge auch beim Schreiben in diese durcheinander geraten.
System.in ist so eine Sache… Erstens blockiert es ja solange, bis die Eingabe mit Enter/Return abgeschlossen wurde und zweitens wird dieses Enter/Return nicht mit in den Buffer geschrieben und man muss es deswegen beim ProcessStream explizit mit anhängen (OS spezifisches NEW_LINE). Tut man dieses nicht, blockiert der Thread, welcher die Tastatur im Prozess abfragt weiter und wird evtl. erst bei Prozessende ausgegeben, wenn der Stream dort geflusht wird.


#7

ich denke nein, schon bei einem Thread kann es durcheinander geraden, siehe Beispielprogramm

und etwa die Eclipse-Konsole stellt doch System.err rot da, wie sollte das bei nur einem Stream gehen?


https://bugs.eclipse.org/bugs/show_bug.cgi?id=32205

die Antwort im Bug

No plans to address this in 2.1. This has been improved since 2.0, but since
writing/reading from out/err streams is non-deterministic (i.e. we have
seperate threads reading output from each stream), the result can be non-
deterministic.

könnte auch hier gelten, bei zwei Streams mit beliebigen neuen Zeilen gibt es vielleicht keine denkbare Möglichkeit, die Reihenfolge sicherzustellen,
ja wenn der Sender an jede Zeile eine Zeitstempel anfügen würde :wink:

edit:

This test works fine in command line mode outside Eclipse.

klingt natürlich bisschen anders, was ist denn da konkret der Unterschied?


#8

Nur kurz

AFAIK wird die Standardausgabe gepuffert und die Errorausgabe nicht. Dies würde zumindest das zeitliche Verhalten erklären. Mir wurde bei Ubuntuusers.de empfohlen die Standardausgabe auf die Errorausgabe umzuleiten. Hatte das Projekt allerdings dann verworfen und die Umleitung nicht mehr ausprobiert.


#9

[QUOTE=SlaterB]klingt natürlich bisschen anders, was ist denn da konkret der Unterschied?[/QUOTE]Ich nehme stark an, dass dieses Durcheinander in der Reihenfolge erst zustande kommt, wenn man das über Prozessstreams laufen lässt (SingleThread im Prozess vorrausgesetzt), so wie es Eclipse ja auch macht (man hat da nicht groß die Wahl). Ob das 2 verschiedene Printstreams werden, ist anscheinend OS abhängig und auch nicht wirklich so entscheident, weil man eh beide setzen kann, wie man will (obwohl, was hätte man davon, wenn man die ConsoleStreams nicht schachtelt).

Edit: Wobei… eigentlich müsste einem doch auffallen, dass es in Gängigen Betriebssystemen eh’ nur eine Ausgabe pro Console gibt und damit auch nur einen Stream (auf nativer Seite zumindest). Gepuffert sind jedenfalls beide Streams (siehe “java.lang.System.initializeSystemClass()”).