Socket / Threading-Problem: Die Undo-Operation hat einen Kontext gefunden, der sich von dem unterscheidet, der in der entsprechenden Set-Operation angewendet wurde

8

Ich habe Probleme mit dem oben genannten Fehler. Wir haben eine TCP / IP-Server-Anwendung, die seit einigen Jahren funktioniert. Ich muss nun zulassen, dass die Anwendung Verbindungen von direkt angeschlossenen USB-Geräten akzeptiert, indem intern eine Socket-Verbindung verwendet wird, um einen Patch zu localhost (127.0.0.1) innerhalb der Server-Anwendung durchzuführen. (Übrigens erwähne ich den USB nur, um zu erklären, warum ich das tue - ich habe alle USB-Funktionen als Teil des Debuggens dieses Problems deaktiviert).

Die Kommunikation entlang dieses Sockets kann Aufrufe von GUI-Elementen sowohl auf der Client- als auch auf der Serverseite zur Folge haben. Zugriffe auf GUI-Elemente auf der Client-Seite verursachen den Fehler im Titel (Aufruf-Stack unten). Eines der Hauptprobleme hierbei ist, dass der Debugger die Ausnahmebedingung nicht anhalten kann: Obwohl alle Ausnahmen so eingestellt sind, dass sie anhalten, wenn sie ausgelöst werden, wird die Anwendung einfach beendet, wenn der Fehler auftritt.

Das Einzige, was an meiner Anwendung einzigartig erscheint, ist, dass sie einen internen Socket verwendet, um sich mit 127.0.0.1 zu verbinden. Ich habe auch bestätigt, dass die Anwendung funktioniert, wenn der Client in eine separate Anwendung getrennt ist. Allerdings kann ich dies aus anderen Gründen nicht als dauerhafte Lösung nutzen.

Es gibt mehrere Beiträge, die diese Art von Problemen diskutieren, die ich unten aufgelistet habe. Leider scheint mir in meinem Fall keine Lösung zu bieten:

  • In den meisten verwandten Posts wird erläutert, dass alle GUI-Vorgänge im GUI-Thread mithilfe von Invoke oder BeginInvoke durchgeführt werden müssen. Ich bin zuversichtlich, dass meine Anwendung das richtig ausführt (es erhält ein Formular, das Application.Forms verwendet, um das Hauptformular zu erhalten, und ruft Invoke für dieses auf), und hat in dem Debugger doppelt überprüft.
  • In Bezug auf das Obige gibt es eine Diskussion bezüglich der Verwendung von Invoke vs BeginInvoke, um zu blockieren / nicht zu blockieren. In meinem Fall haben beide das gleiche Ergebnis.
  • Einige Beiträge schlagen vor, dass es notwendig ist, die Sockets selbst auf dem GUI-Thread zu erstellen (meins sind).
  • Dieser erklärt, dass Sie das bekommen können Fehler, wenn Sie DoEvents in Ihrer Anwendung verwenden (nicht).
  • Dieser bedeutet auch, dass Sie bekommen könnten der Fehler mit einem fehlenden EndConnect-Aufruf, wenn asynchrone Aufrufe für die Client-Socket-Verbindung verwendet werden (meine Clientverbindung ist synchron).
  • This one erklärt, dass Sie von InvokeRequired falsche Ergebnisse erhalten können, wenn das Fensterhandle noch nicht erstellt wurde (dies wurde mit IsHandleCreated überprüft).
  • Dieser Eintrag von Microsoft Connect meldet einen ähnlichen Fehler, hat aber keine Lösung (microsoft forscht seit 2006 daran!)
  • Dieser enthält einen Vorschlag zur Verwendung von AsyncOperationManager .SynchronizationContext, um den Synchronisierungskontext zu sichern / wiederherzustellen, was (nicht überraschend?) Nur verschiedene Fehler verursacht.
  • Es gibt ein paar Posts, die darauf hindeuten, dass der Fehler nur Debugging ist, und das folgende wird es weggehen lassen - aber ich habe mich nicht darum gekümmert:
    System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false

Es gibt andere Beiträge, die ähnliche Fragen stellen: hier , hier und hier . Ein guter hier auch.

Hier ist ein Code-Snippet - dies verursacht einen Absturz in ProcessCommandCT, wenn Socket-Daten vom Client empfangen werden:

%Vor%

Ich verwende VB .NET 2010 mit .NET4.

Danke für jede Hilfe - ich hoffe, dass die konsolidierte Liste der obigen Beiträge auch anderen hilft.

Tim

Anrufliste:

%Vor%     
ttt 28.09.2010, 12:03
quelle

2 Antworten

2

Diese Ausnahme tritt auf, wenn sich die ExecutionContext-Eigenschaft eines Threads ändert. Insbesondere wenn dieser Thread ein Threadpool- oder E / A-Vervollständigungsthread ist, der einen Rückruf ausführt und dessen ExecutionContext von einem anderen Thread abgerufen wurde, der einen BeginXxx-Aufruf zum Starten eines asynchronen Vorgangs ausgeführt hat. Wie Socket.BeginReceive ().

Es gibt reichlich Gelegenheit dafür, dass es im geposteten Code passiert, da es mit den Formularen im Callback bastelt. ExecutionContext hat eine versteckte Eigenschaft mit dem Namen SynchronizationContext, die SynchronizationContext.Current verfolgt. Winforms installiert einen benutzerdefinierten Synchronisierungsanbieter, wenn ein Formular zum ersten Mal erstellt wird. Erforderlich, um Aufrufe von einem Arbeitsthread ordnungsgemäß an den UI-Thread zu vermitteln. Es ist eine Klasse, die von SynchronizationContext namens WindowsFormsSynchronizationContext abgeleitet ist.

Der wahrscheinlichste Fehlermodus ist daher, dass die Methode sock_Receive () aufgerufen wird, bevor alle Winforms-Formulare erstellt werden. Mit dem Formularerstellungscode den Synchronisierungsanbieter installieren und den ExecutionContext ändern und damit den Code mit der Ausnahme abstürzen. Ein solches Problem muss behoben werden, indem die Initialisierung der App geändert wird und sichergestellt wird, dass ein Hauptformular vorhanden ist, bevor Sie asynchronen Code für die Verwendung von BeginInvoke () zulassen.

    
Hans Passant 13.04.2012 00:51
quelle
0

Können Sie den Code anzeigen, wo Sie IO ausgeben und beenden?

Hier ist eine mögliche Problemumgehung: Lassen Sie synchronisationcontext.current auf null setzen, während Sie alle IO-Operationen beginnen. Es sieht so aus, als ob etwas im .NET-Framework verwirrt wird und versucht, den Ausführungskontext zweimal wiederherzustellen.

Hier ist ein nützlicher Helfer:

%Vor%

Nennen Sie es so:

%Vor%

Noch eine Frage: Verschachteln Sie IO-Aufrufe? Geben Sie viele kleine IOs auf diesem Sockel aus? Ich frage das, weil der Rahmen hier einen Sonderfall hat:

%Vor%

Dieser Codeabschnitt lässt den Verdacht aufkommen, dass es in diesem seltenen Fall einen Fehler im .NET-Framework gibt. ThreadPool.QueueUserWorkItem wird den aktuellen ExecutionContext erfassen und später wiederherstellen, was wir in der Stack-Ablaufverfolgung sehen.

    
usr 12.04.2012 21:43
quelle