2014-10-15 18 views
9

Sto codificando un'applicazione e ho un problema con un deadlock.Deadlock durante la scrittura su Process.StandardInput

Il mio codice è così:

Process p = new Process(); // That using an other application 

allora ho per inviare un file .xml a questo processo in modo che uso

XmlSerializer xs = new XmlSerializer(data.GetType()); 
using (var ms = new MemoryStream()) 
{ 
    var sw = new StreamWriter(ms); 
    XmlWriter xmlwriter = XmlWriter.Create(sw, xmlWriterSettings); 
    xmlwriter.WriteProcessingInstruction("PipeConfiguratorStyleSheet", processing); 
    xs.Serialize(xmlwriter, data); 
    xmlwriter.Flush(); 
    ms.Position = 0; 
    var sr = new StreamReader(ms); 
    while (!sr.EndOfStream) 
    { 
     String line = sr.ReadLine(); 
     p.StandardInput.WriteLine(line);     
     Console.WriteLine(line); 
     p.BeginOutputReadLine(); 
     p.CancelOutputRead(); 
    } 
} 

Quindi, in realtà posso inviare una parte del mio .xml-file al mio processo ma in un momento, otterrò un punto morto. Non so come usare correttamente BeginOutputReadLine() Penso.

+0

non esiste un metodo per utilizzare direttamente l'istanza di processo come flusso? come 'xs.Serialize (p.StandardInput, data)'? –

+0

Sei sicuro che il lato ricevente stia leggendo i dati? Se il lato ricevente non sta leggendo quando il buffer si riempie, puoi essere bloccato. Hai il codice per il lato ricevente? –

+0

come si incontra la situazione di stallo? Te lo chiedo, perché non c'è il 'lock' - quindi non è del tutto ovvio, per me, come dovrebbe esserci un blocco (che potrebbe essere descritto come un deadlock) ... –

risposta

1

Prima di tutto, perché non si usa il Process.StandardInput -property direttamente come bersaglio, come

var process = new Process 
{ 
    // all your init stuff 
}; 
var xmlSerializer = new XmlSerializer(data.GetType()); 
var xmlwriter = XmlWriter.Create(process.StandardInput, xmlWriterSettings); 
xmlSerializer.Serialize(xmlwriter, data); 

In caso contrario, il msdn-entry dà un howto chiaro per l'utilizzo di Process.BeginOutputReadLine(), che è possibile rimodellare a

var autoResetEvent = new AutoResetEvent(false); // this mutex acts as our bouncer for the reading-part 
var process = new Process 
{ 
    // all your init stuff 
}; 
process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.OutputDataReceived += (sender, args) => { 
    // TODO you could read the content here with args.Data 
    autoResetEvent.Set(); 
}; 
process.Start(); 

using (var memoryStream = new MemoryStream()) 
{ 
    using (var streamWriter = new StreamWriter(memoryStream)) 
    { 
     var xmlSerializer = new XmlSerializer(data.GetType()); 
     var xmlwriter = XmlWriter.Create(streamWriter, xmlWriterSettings); 
     xmlSerializer.Serialize(xmlwriter, data); 
    } 
    memoryStream.Position = 0; 
    using (var streamReader = new StreamReader(memoryStream)) 
    { 
     while (!streamReader.EndOfStream) 
     { 
      var line = streamReader.ReadLine(); 
      process.StandardInput.WriteLine(line); 

      Console.WriteLine(line); 

      process.BeginOutputReadLine(); 
      autoResetEvent.WaitOne(); 
     } 
    } 
} 

// TODO closing the process.StandardInput, exiting process, ... 

In ogni caso - so che questo dovrebbe essere un commento - c'è un motivo specifico per cui stai aspettando che il tuo processo scriva qualcosa?

Il flusso di StandardOutput può essere letto in modo sincrono o asincrono. Metodi come Read, ReadLine e ReadToEnd eseguono operazioni di lettura sincrona sul flusso di output del processo. Queste operazioni di lettura sincrona non vengono completate fino a quando il Processo associato non scrive sul suo stream StandardOutput o chiude il flusso. Al contrario, BeginOutputReadLine avvia le operazioni di lettura asincrona sul flusso StandardOutput . Questo metodo abilita un gestore di eventi designato per l'output del flusso e restituisce immediatamente al chiamante, che può eseguire mentre l'output del flusso viene indirizzato al gestore dell'evento .

Il che significa, che se il processo non scrivere nulla (e si è in attesa), si girano per la risposta senza fine ...

EDIT

Si dovrebbe inoltre aggiungere un gestore a Process.ErrorDataReceived come

process.StartInfo.RedirectStandardError = true; 
process.ErrorDataReceived += (sender, args) => { 
    // TODO do something with the response of args.Data 
    autoResetEvent.Set(); 
}; 

e

while (!streamReader.EndOfStream) 
{ 
    var line = streamReader.ReadLine(); 
    process.StandardInput.WriteLine(line); 

    Console.WriteLine(line); 

    process.BeginOutputReadLine(); 
    process.BeginErrorReadLine(); 
    autoResetEvent.WaitOne(); 
} 

per gestire anche casi di errore (qualunque cosa ciò possa significare).

+0

Il programma non funziona così per me. Cercherò di risolvere gli errori con le tue risposte e di inviare il codice finale .Specchio, –

+0

Ciao, dopo alcuni dati di stampa ho ricevuto questo errore: Un'operazione di lettura asincrona è già stata avviata nello stream. Sai come posso risolvere questo? Tha nk di. –

+0

@SteevenBrunner Questo succede quando chiamate '.BeginOutputReadLine()' senza essere precedentemente richiamati con '.OutputDataReceived'. Questo è il motivo per cui ho usato 'AutoResetEvent'. Quale approccio hai effettivamente provato e quale stai attualmente utilizzando? Potresti inserire queste informazioni nella tua domanda? –

Problemi correlati