2016-04-16 6 views
2

HintergrundRe-Synchronisierung Process.RedirectStandardOutput

Ich bin ein C# Wrapper für eine node.js Anwendung zu schreiben. In diesem Wrapper lese ich kontinuierlich die Standardausgabe über Process.RedirectStandardOutput. Das Ereignis ist an die Funktion onOutputDataReceived in einer Instanz der Klasse ProcessManager gebunden. In derselben Instanz gibt es auch eine Instanz eines benutzerdefinierten Ereignissystems.

[ProcessManager]

EventSystem eventSystem; 

private void Start() 
{ 
    [...] 

    process.OutputDataReceived += onOutputDataReceived; 

    [...] 
} 

private void onOutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    [...] 

    eventSystem.call(eventName, args); 
} 

[EventSystem]

List<EventHandler> eventList; 

public Boolean call(String eventName, dynamic args) 
{ 
    [...] 

    foreach (EventHandler handler in eventList) 
    { 
     handler(args); 
    } 

    [...] 
} 

Das Problem tritt auf, wenn das Ereignis aufgerufen wird. Hier ist ein Beispiel aus einer winforms-Anwendung, die meinen Wrapper verwendet.

Wrapper.ProcessManager procMan; 

procMan.eventSystem.on(eventName, (a) => 
    { 
     button1.Text = someValue; 
    }); 

Sobald er ausgeführt wird, stürzt die Anwendung mit der Meldung

Cross-Thread-Betrieb nicht gültig: Control 'button1' von einem Thread zugegriffen andere als das Gewinde auf erstellt wurde

Meine Frage, wie ich es verstehe, ist dies:

onOutputDataReceived wird asynchron in einem eigenen Thread ausgeführt. Da derselbe Thread, der nur die Ausgabe verarbeiten soll, die Ereignisse fortsetzt, bin ich unbeabsichtigt Multithreading in meinem Wrapper, was das Leben für jeden, der ihn implementiert, erschwert.

Grundsätzlich,

ich brauche die Leitung eventSystem.call() in demselben Thread auszuführen, die den Rest der ProcessManager Instanz halten, sobald neue Ausgangsdaten wie möglich empfangen wurden. Irgendwelche Ideen, wie dies am besten erreicht werden kann?


Eine Lösung dachte ich habe von so etwas wie dieses

[ProcessManager]

Queue<string> waiting = new Queue<string(); 
EventSystem eventSystem; 

private void onOutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    [...] 
    waiting.Enqueue(eventName); 
} 

private void WhenReady() 
{ 
    while(waiting.Count > 0) 
     eventSystem.call(waiting.Dequeue()); 
} 

Soweit ich sehen kann, dies würde bedeuten, eine Art Polling jedes x Millisekunden, die sich nicht wie eine saubere Lösung anfühlt. Es scheint mir auch so, als wäre eine solche Lösung viel zu teuer für den Fall, dass keine Nachrichten empfangen werden und zu langsam für einige.

Antwort

2

Der Code, der den Prozess nodejs ausführt und seine Ausgabe liest, sollte nicht über die Threading-Anforderungen von Ereignisteilnehmern Bescheid wissen müssen. Machen Sie den Teilnehmer seine eigenen Anforderungen erfüllen:

(a) => 
{ 
    Invoke(new Action(() => button1.Text = someValue)); //marshal to UI thread 
} 

Ihre vorläufige Lösung würde nicht funktionieren, weil sie den UI-Thread blockieren würde.

Außerdem wird waiting in einer unsynchronisierten Weise verwendet ... Dies ist ein nicht zusammenhängender Fehler.

+0

Ich habe noch nicht so darüber nachgedacht (noch nicht an Multithreading gewöhnt), aber es macht Sinn. –