Unterprozess readline hängt und wartet auf EOF

Lesezeit: 6 Minuten

Ich habe ein einfaches C++-Programm, das ich über ein Python-Skript auszuführen versuche. (Ich bin sehr neu im Schreiben von Skripten) und ich habe Probleme beim Lesen der Ausgabe durch die Pipe. Nach dem, was ich gesehen habe, scheint es, als würde readline() ohne EOF nicht funktionieren, aber ich möchte in der Lage sein, mitten im Programm zu lesen und das Skript auf die Ausgabe reagieren zu lassen. Anstatt die Ausgabe zu lesen, hängt es einfach das Python-Skript auf:

#!/usr/bin/env python
import subprocess
def callRandomNumber():
    print "Running the random guesser"
    rng=subprocess.Popen("./randomNumber", stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
    i=50
    rng.stdin.write("%dn" % i)
    output=rng.stdout.readline()
    output=rng.stdout.readline()
callRandomNumber()

und die c++-Datei, die eine Zufallszahl zwischen eins und 100 generiert, überprüft dann die Vermutung des Benutzers, bis er richtig geraten hat

#include<iostream>
#include<cstdlib>
using namespace std;

int main(){
  cout<<"This program generates a random number from 1 to 100 and asks the user to enter guesses until they succuessfully guess the number.  It then tells the user how many guesses it took them"<<endl;
  srand(time(NULL));
  int num=rand()%100;
  int guessCount=0;
  int guess=-1;
  cout<<"Please enter a number:  ";
  cin>>guess;
  while(guess!=num){
    if(guess>num){cout<<"That guess is too high.  Please guess again:  ";}
    else{cout<<"That guess is too low.  Please guess again:  ";}
    cin>>guess;
    guessCount++;
  }
  cout<<"Congratulations!  You solved it in "<<guessCount<<" guesses!"<<endl;
  return 0;
}

Das letztendliche Ziel ist, dass das Skript das Problem mit einer binären Suche löst, aber im Moment möchte ich nur eine Zeile lesen können, ohne dass dies das Ende der Datei ist

Unterprozess readline hangt und wartet auf EOF
jfs

Wie @Ron Reiter betonte, können Sie nicht verwenden readline() weil cout druckt nicht implizit Zeilenumbrüche – Sie müssen es auch std::endl oder "n" Hier.

Für eine interaktive Verwendung, wenn Sie das untergeordnete Programm nicht ändern können, pexpect Modul bietet mehrere bequeme Methoden (und im Allgemeinen Es löst kostenlos: Eingabe/Ausgabe direkt vom/zum Terminal (außerhalb von stdin/stdout) und Probleme mit der Blockpufferung):

#!/usr/bin/env python
import sys

if sys.version_info[:1] < (3,):
    from pexpect import spawn, EOF # $ pip install pexpect
else:
    from pexpect import spawnu as spawn, EOF # Python 3

child = spawn("./randomNumber") # run command
child.delaybeforesend = 0 
child.logfile_read = sys.stdout # print child output to stdout for debugging
child.expect("enter a number: ") # read the first prompt
lo, hi = 0, 100
while lo <= hi:
    mid = (lo + hi) // 2
    child.sendline(str(mid)) # send number
    index = child.expect([": ", EOF]) # read prompt
    if index == 0: # got prompt
        prompt = child.before
        if "too high" in prompt:
            hi = mid - 1 # guess > num
        elif "too low" in prompt:
            lo = mid + 1 # guess < num
    elif index == 1: # EOF
        assert "Congratulations" in child.before
        child.close()
        break
else:
    print('not found')
    child.terminate()
sys.exit(-child.signalstatus if child.signalstatus else child.exitstatus)

Es funktioniert, aber es ist daher eine binäre Suche (traditionell) könnte es Fehler geben.

Hier ist ein ähnlicher Code, der verwendet subprocess Modul zum Vergleich:

#!/usr/bin/env python
from __future__ import print_function
import sys
from subprocess import Popen, PIPE

p = Popen("./randomNumber", stdin=PIPE, stdout=PIPE,
          bufsize=1, # line-buffering
          universal_newlines=True) # enable text mode
p.stdout.readline() # discard welcome message: "This program gener...

readchar = lambda: p.stdout.read(1)
def read_until(char):
    buf = []
    for c in iter(readchar, char):
        if not c: # EOF
            break
        buf.append(c)
    else: # no EOF
        buf.append(char)
    return ''.join(buf).strip()

prompt = read_until(':') # read 1st prompt
lo, hi = 0, 100
while lo <= hi:
    mid = (lo + hi) // 2
    print(prompt, mid)
    print(mid, file=p.stdin) # send number
    prompt = read_until(':') # read prompt
    if "Congratulations" in prompt:
        print(prompt)
        print(mid)
        break # found
    elif "too high" in prompt:
        hi = mid - 1 # guess > num
    elif "too low" in prompt:
        lo = mid + 1 # guess < num
else:
    print('not found')
    p.kill()
for pipe in [p.stdin, p.stdout]:
    try:
        pipe.close()
    except OSError:
        pass
sys.exit(p.wait())

Ich bin mir ziemlich sicher, dass das Hinzufügen von Zeilenumbrüchen in Ihrem C++-Programm dazu führt, dass die Readlines zurückgegeben werden.

  • Ja, aber ich möchte in der Lage sein, Skripte für vorhandene Programme zu erstellen, anstatt Programme an die Skripte anzupassen

    – Ryan Haining

    26. Oktober 11 um 1:25 Uhr

  • Es gibt keine generische Möglichkeit, EOF-Probleme zu “lösen”. Woher wissen Sie sonst, dass die Leitung tatsächlich zu Ende ist? Wenn Sie das Programm kennen, lesen Sie nicht bis zu einem Zeilenumbruch, lesen Sie einfach die genaue Anzahl an Zeichen, die Sie benötigen. Andernfalls geben Sie einen Zeilenumbruch zurück. Ihre andere Alternative ist die Verwendung von Zeitüberschreitungen, was wirklich schlecht ist.

    – Ron Reiter

    2. November 11 um 7:14 Uhr

  • Sie müssen nicht den genauen Betrag lesen. Es reicht aus, wenn Sie fast synchron sind (OS-Pipe-Puffer bietet Toleranz).

    – jfs

    22. Mai 14 um 0:28 Uhr

Möglicherweise müssen Sie explizit schließenstdinsodass der untergeordnete Prozess aufhört zu hängen, was meiner Meinung nach mit Ihrem Code passiert – dies kann überprüft werden, indem Sie top auf einem Terminal ausführen und prüfen, ob randomnumberDer Status von bleibt im Ruhezustand und wenn es nach der erwarteten Zeit, die es für die Ausführung benötigen würde, 0 % CPU verwendet.

Kurz gesagt, wenn Sie hinzufügen rng.stdin.close() gleich nach dem rng=subprocess(...) anrufen, kann es ohne Probleme fortgesetzt werden. Eine andere Option wäre zu tun output=rng.communicate(stdin="%dn" % i)und anschauen output[0]undoutput[1]wer sind stdout und stderr, bzw. Infos findest du untercommunicate Hier.

  • Wow, ich habe vergessen, dass es diese Frage gibt. Wenn Sie stdin schließen, können Sie nicht mehr mit dem Prozess kommunizieren, was in diesem Fall erforderlich ist, um dynamisch auf die Ausgabe zu reagieren

    – Ryan Haining

    20. Mai ’14 um 14:39 Uhr

  • Exakt. Ich denke, Sie sollten der Antwort vielleicht ein Update hinzufügen, damit andere Leser die wahre Ursache des Aufhängens verstehen, was höchstwahrscheinlich der Grund ist, warum sie jemals hier ankommen. Außerdem hätte ich nichts dagegen, wenn Sie meine Antwort verbessern würden 🙂

    – Lord Henry Wotton

    20. Mai ’14 um 17:22 Uhr

  • @RyanHaining: Ihr C++-Code überprüft EOF auf stdin nicht und ruft daher auf rng.stdin.close() führt in Ihrem Fall vorzeitig zu einer Endlosschleife. ich würde … benutzen pexpect oder in diesem Fall sein Windows-Analogon.

    – jfs

    21. Mai 14 um 23:39 Uhr

  • @RyanHaining +1 für das Zitieren pexpect, was für mich völlig neu ist und für andere Leser vielleicht auch sein könnte. Würde es Ihnen etwas ausmachen, näher darauf einzugehen, wie es bei dem gegebenen Problem helfen würde?

    – Lord Henry Wotton

    22. Mai ’14 um 14:52 Uhr

  • @LordHenryWotton Ich glaube nicht, dass du mich damit markieren wolltest, aber JF Sebastian hat eine vollständige Antwort gepostet, die ausführlicher ist

    – Ryan Haining

    22. Mai ’14 um 15:10 Uhr

.

571570cookie-checkUnterprozess readline hängt und wartet auf EOF

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy