Threads - Join() und ManualResetEvent()

24/02/2011 - 13:45 von Josef Morlo | Report spam
Hallo,
Ich habe zwei Fragen zu Threads, zu Join und ManualResetEvent im
besonderen.

Ein (Übungs-)Programm mit folgender Struktur: Mehrere Threads mit jeweils
Threadprozedur. Darin jeweils eine Schleife, StopFlag und Rückruf.
Schematisch:

Public Class Form1
Private mThread1 as Thread

Private mThreadN as Thread
Private mStopFlag as Boolean
Private mThreadCounter as Integer
Private Delegate Sub DelClosingForm()

Sub ThreadProc1()
While not mStopFlag
SyncLock(me)
'Tut was mit Zàhlern und Aktualisierung von Steuerelementen
End SyncLock
End While
'Rückmeldung, wenn Schleifendurchlauf beendet
Invoke(New DelClosingForm(AddressOf CloseForm))
End Sub

Analog die weiteren Thread-Prozeduren

Private Sub btnStart_Click(…)
mThread1 = New Thread(New ThreadStart(AddressOf ThreadProc1))
mThread1.Start()
mThreadCounter +=1

mThreadN = New Thread(New ThreadStart(AddressOf ThreadProcN))
mThreadN.Start()
mThreadCounter +=1

Form schließen

Private Sub btnExit_Click(…)
Me.Close()
End Sub

Private Sub Form1_FormClosing(…)
If mThreadCounter <> 0 Then
mStopFlag = True
e.Cancel = True
End If

'Alternativ zu CloseForm und Delegate:
'mStopFlag = True
'Do Until mThreadCounter = 0
'Application.DoEvents()
'Loop
End Sub

Sub CloseForm()
'Rückmeldung aller Threads abpassen
mThreadCounter -= 1
If mThreadCounter = 0 Then
Me.Close()
End If
End Sub
End Class

Das funktioniert auch soweit, Schleifendurchlàufe und Threads werden
ordnungsgemàß beendet.

Erste Frage:
Ist es im konkreten Fall zwingend notwendig, In- und Dekrementierung des
Threadzàhlers abzusperren, also etwa so:

mThreadCounter = Max(Interlocked.Increment(mThreadCounter), _
(mThreadCounter - 1)) ?

Zweite Frage:
Wenn ich die Threadkonzepte recht verstanden habe, so müsste sich doch auch
die Möglichkeit bieten, den Haupthread warten zu lassen (Join) bzw. ein
Signal zu setzen (ManualResetEvent), bis bzw. wenn die Nebenthreads den
Schleifendurchgang abgeschlossen haben. Ich finde keinen Ansatzpunkt. Wie
müsste man das einbauen?

Danke für Ideen
Grüße

Josef Morlo
 

Lesen sie die antworten

#1 Armin Zingler
24/02/2011 - 16:39 | Warnen spam
Am 24.02.2011 13:45, schrieb Josef Morlo:
Hallo,
Ich habe zwei Fragen zu Threads, zu Join und ManualResetEvent im
besonderen.

Ein (Übungs-)Programm mit folgender Struktur: Mehrere Threads mit jeweils
Threadprozedur. Darin jeweils eine Schleife, StopFlag und Rückruf.
Schematisch:

[...]

Das funktioniert auch soweit, Schleifendurchlàufe und Threads werden
ordnungsgemàß beendet.

Erste Frage:
Ist es im konkreten Fall zwingend notwendig, In- und Dekrementierung des
Threadzàhlers abzusperren, also etwa so:

mThreadCounter = Max(Interlocked.Increment(mThreadCounter), _
(mThreadCounter - 1)) ?



Da die Inkrementierung/Dekrementierung ausschliesslich im
UI-Thread stattfindet, ist Interlocked.Increment/Decrement
nicht erforderlich.

Im allgemeinen: Wofür verwendest du die Max-Funktion?
Ich würde einfach nur schreiben:

Interlocked.Increment(mThreadCounter)

und

NewCounter = Interlocked.Decrement(mThreadCounter)
if Newcounter = 0 ...


Zweite Frage:
Wenn ich die Threadkonzepte recht verstanden habe, so müsste sich doch auch
die Möglichkeit bieten, den Haupthread warten zu lassen (Join) bzw. ein
Signal zu setzen (ManualResetEvent), bis bzw. wenn die Nebenthreads den
Schleifendurchgang abgeschlossen haben. Ich finde keinen Ansatzpunkt. Wie
müsste man das einbauen?



Dann wàre der UI-Thread aber gesperrt und das Interface "reagiert nicht".

Rein technisch gesehen: Du könntest pro Thread ein ManualResetEvent
erzeugen. Das müsstest du aber im Hintergrundthread selbst setzen,
denn Invoke würde zum dead-lock führen weil der UI-Thread
ja auf das Ende wartet. Das Warten ginge dann mit WaitHandle.WaitAll()
wobei du ein Array von ManualResetEvents übergeben kannst. Wenn
alle signalisiert sind, also alle Threads beendet, kehrt WaitAll
zurück.

Join bezieht sich nur auf /einen/ Thread. Wenn dieser ebenfalls
Invoke verwendet, kàme es ebenso zum dead-lock.


Armin

Ähnliche fragen