Deadlock bei RemoveHandler

11/05/2009 - 03:07 von Armin Zingler | Report spam
Hi,

heut kommt's aber Dicke... ;)

Thread T1 ist der UI-Thread. Darin erzeugt wurde das Control C.
In Thread T2 löst das Objekt O das Event E1 aus. Im Ereignishandler wird
C.Invoke aufgerufen. In der per Invoke aufgerufenen Methode wird
"RemoveHandler O.E2,..." ausgeführt.

Problem ist ein Deadlock bei Removehandler. Dass in Thread T2 derzeit
C.Invoke den Thread blockiert, ist klar. Ich verstehe aber nicht, warum
Removehandler blockiert.

Konkret ist E1=Process.Exited und E2=Process.OutputDataReceived


Callstack für Thread T1:

[Deaktiviert oder wartend]

System.dll!System.Diagnostics.Process.remove_OutputDataReceived




Callstack für Thread T2 ist (erwartungsgemàß):

[Deaktiviert oder wartend]
mscorlib.dll!System.Threading.WaitHandle.WaitOne
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke

bla.exe!bla.Form1.OnExited Zeile 102 + 0x71 Bytes




Ich verstehe nicht, warum Thread T1 wartet. Weiß das jemand? Im IL-Code zu
remove_OutputDataReceived ist nichts davon zu sehen.

Ich scheine generell etwas bzgl Threadsicherheit von Removehandler übersehen
zu haben. Ist das irgendwo dokumentiert? Oder ist Removehandler auch schon
in der Bemerkung über die Notwendigkeit der Synchronisation auf
Instanzmember (wozu auch Events gehören) mit eingeschlossen? (-> muss mich
ja nicht wundern!)


Armin
 

Lesen sie die antworten

#1 Peter Fleischer
13/05/2009 - 08:14 | Warnen spam
Ich versuche es noch eimal, da mein Beitrag gestern scheinbar nicht
angekommen ist.

"Armin Zingler" schrieb im Newsbeitrag
news:%

Hi Armin,
ich habe die Beschreibung - so wie sie verstanden habe - mal nachgestellt
und kann deine Probleme nicht erkennen. Hier meine Testumgebung:

Option Infer On ' Only VB9
Option Strict On

Imports System.Threading

Public Class Form1

Private tb1 As New TextBox With {.Top = 10}

Private c As New C1
Private T1, T2 As Thread

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.Controls.AddRange(New Control() {tb1})
T1 = Thread.CurrentThread
T2 = New Thread(AddressOf c.Sub2)
c.d = AddressOf Prot
AddHandler c.E1, AddressOf Sub1
AddHandler c.E2, AddressOf Sub1
T2.Start()
End Sub

Delegate Sub SubDeleg(ByVal txt As String)

Private Sub Sub1(ByVal txt As String)
Prot("Aufruf Sub1")
If tb1.InvokeRequired Then
Prot("Invoke nötig")
tb1.Invoke(New SubDeleg(AddressOf Sub1), _
New Object() {txt})
Prot("Invoke ausgeführt")
Else
tb1.Text = txt
Prot("vor RemoveHandler")
RemoveHandler c.E2, AddressOf Sub1
Prot("nach RemoveHandler")
End If
End Sub

Private Sub Prot(ByVal txt As String)
Console.WriteLine("{0:mm:ss.fff} {1}, T1: {2}, T2: {3}", _
Now, txt, T1.ThreadState, T2.ThreadState)
End Sub

Friend Class C1
Public Event E1(ByVal txt As String)
Public Event E2(ByVal txt As String)
Public d As SubDeleg
Public Sub Sub2()
d.Invoke("Start Sub2")
Thread.Sleep(500)
d.Invoke("vor RaiseEvent 1")
RaiseEvent E1("Ereignis1")
d.Invoke("nach RaiseEvent 1")
Thread.Sleep(500)
d.Invoke("vor RaiseEvent 2")
RaiseEvent E1("Ereignis2")
d.Invoke("nach RaiseEvent 2")
End Sub
End Class

End Class

Viele Grüsse
Peter

Ähnliche fragen