HELP - Why are Worker thread"s child thread"s entering WaitSleepJoin? Plus Context Deadlock....
am 29.09.2007 22:23:25 von hzgt9bUsing VS2005, VB.NET,
I have a worker thread (started by main UI thread) that in turn
spawns
and monitors child threads to execute several long running process.
The problem is that the worker thread's children are entering
WaitSleepJoin and thus my worker thread just hangs doing nothing and
just loops. My question is why are my child thread's entering
waitsleepjoin state? There is no sleep or spinwait being called in
the
child's thred process.
Also, I am getting the dreaded content deadlock and con't figure out
why:
The CLR has been unable to transition from COM context 0x1d1ba0 to
COM
context 0x1d1e80 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or
processing a very long running operation without pumping Windows
messages. This situation generally has a negative performance impact
and may even lead to the application becoming non responsive or
memory
usage accumulating continually over time. To avoid this problem, all
single threaded apartment (STA) threads should use pumping wait
primitives (such as CoWaitForMultipleHandles) and routinely pump
messages during long running operations.
The deadlock even happens if the code in StartUpload (worker thread's
process - see full lisiting below) executes to the end (which I
thought would cause the worked thread to Stop). How can I determine
where the deadlock is? BTW, I've tried diabling MDA's LoadLock
exception and adding a ...mda.config file to no avail (I don't think
that VS is starting the debugger starting the MDA erronously).
Beow are some code excerpts that show (1) the start of the worker
thread; (2) code in the work thread's proc that spawns and monitors
child threads and (3) the child thread proc. Let me know if you see
any problems.
One thing I'm not sure about - that's is the number of event's that I
am raising. These events are handled in my main UI thread so the user
can get status updates. The event handlers are invoking delegate
functions (so they run on the main UI thread) using BeginInvoke in
attempts to avoid blocking on the RaiseEvent calls in the worker
thread.
Selected code excerpts follow:
------------------------------------------------------------ ---------------=
=AD-------------------------------
Private Sub btnUpload_Click(ByVal sender As System.Object, ByVal
e
As System.EventArgs) Handles btnUpload.Click
Try
Dim xRoot As XmlElement =3D xDataDocument.DocumentElement
'xDataDocument is an XML having info about audio files...
Dim xNodeList As XmlNodeList =3D xRoot.SelectNodes("//
audioFile[bConvertedToMp3=3D'true' and bUploaded=3D'false']/strFilename")
'gets a list of all the files that need to be uploaded to the
server...
If xNodeList Is Nothing OrElse xNodeList.Count <=3D 0 Then
Else
Me.Uploader =3D New Upload(Me.strCI_Id, xNodeList)
'Me.Uploader.StartUpload() 'COMMENTED OUT, NOW RUNS N
SEPERATE WORKED THREAD
Me.tUpload =3D New Thread(New ThreadStart(AddressOf
Me.Uploader.StartUpload))
Me.tUpload.Priority =3D ThreadPriority.Normal
Me.tUpload.SetApartmentState(ApartmentState.STA)
Me.tUpload.Start() 'STARTS THE WORKER THREAD
End If
xNodeList =3D Nothing
Catch ex As Exception
Debug.WriteLine(ex.Message & vbNewLine & ex.StackTrace)
'TODO handle upload error
End Try
End Sub
------------------------------------------------------------ ---------------=
=AD-------------------------------
Public Sub StartUpload()
'Private Sub Process_Upload()
If Me.xNodeList Is Nothing OrElse Me.xNodeList.Count <=3D 0
Then
Throw New Exception("No files to upload (xNodeList is
empty)")
Else
Try
Me.bRunning =3D True
RaiseEvent DisableUploadAction() 'ALL RAISED EVENTS
ARE INVOKED USING BeginInvoke (asynchronously) TO AVOID BLOCKING
WHILE
THE UI GETS UPDATED
RaiseEvent ChangeUploadButtonTooltip("Uploading
file(s)")
Dim intNumberFiles =3D Me.BuildUploadDataSet()
'Converts
xNodeList to a DataSet so we can just send an XML string up to the
server..
RaiseEvent StatusChange("Starting upload of " &
intNumberFiles & " file" & IIf(intNumberFiles =3D 1, "", "s"))
'Send upload list to the server, get a confirmation
list back...
Dim objWebService As New myWebServiceClass
Try
Me.strUploadFileList =3D
objWebService.UploadFileList(strCI_Id, dsUpload.GetXml)
Catch ex As Exception
Debug.WriteLine(ex.Message & vbNewLine &
ex.StackTrace)
Throw ex
End Try
If InStr(Me.strUploadFileList.ToUpper, "ERROR") =3D 1
Then
RaiseEvent StatusChange("Error registering upload
file list for CIID=3D" & strCI_Id & "..." & Replace(strUploadFileList,
"ERROR", ""))
Throw New Exception("Error registering upload
request for CIID=3D" & strCI_Id & "..." & Replace(strUploadFileList,
"ERROR", ""))
Else
Try
Dim dsFileList As DataSet =3D New DataSet
Dim srReader As New
StringReader(Me.strUploadFileList)
dsFileList.ReadXml(srReader,
XmlReadMode.InferSchema) 'read the strUploadFileList into a dataset
for easies processing below...
Dim dr As DataRow
Dim intFileSize As Int32 =3D 0
Dim intSecs As Double =3D 0
Dim dblProgress As Double =3D 0
Dim strMessage As String =3D Nothing
Dim bProgress As Boolean =3D True
For i As Int32 =3D 0 To
dsFileList.Tables(0).Rows.Count - 1 'For each file in the upload
list....
strMessage =3D "Uploading file " & i + 1 &
"
of " & dsFileList.Tables(0).Rows.Count
RaiseEvent StatusChange(strMessage)
dr =3D dsFileList.Tables(0).Rows(i)
Me.strUploadFileName =3D dr.Item(0)
'If the file has no specified path,
assume
it is in the interview folder
If InStr(Me.strUploadFileName, "\") =3D 0
Then Me.strUploadFileName =3D STR_INTERVIEW & Me.strUploadFileName
Me.dblBytesPerSecond =3D
Me.GetUploadBytesPerSecond() 'Based on past history, speculate an
upload speed in bytes/second
Try
intFileSize =3D
My.Computer.FileSystem.GetFileInfo(Me.strUploadFileName).Len gth
bProgress =3D True
Catch ex As FileNotFoundException
bProgress =3D False
End Try
tsUploadStart =3D Nothing
tsUploadEnd =3D Nothing
Try 'HERE IS WHERE I KICK OFF THE WORK
THREAD'S CHILDREN
If Not Me.tUpload Is Nothing AndAlso
Me.tUpload.IsAlive Then Me.tUpload.Abort()
Me.tUpload =3D Nothing
Me.tUpload =3D New Thread(New
ThreadStart(AddressOf Me.Process_UploadFile))
Me.tUpload.SetApartmentState(ApartmentState.STA)
Me.tUpload.Priority =3D
ThreadPriority.Normal
Me.tUpload.IsBackground =3D True 'Set
this thread to end with parent thread
Me.tUpload.Start()
Catch ex As Exception
Debug.WriteLine("launch of upload
thread failed..." & vbNewLine & ex.Message & vbNewLine &
ex.StackTrace)
If Not Me.tUpload Is Nothing AndAlso
Me.tUpload.IsAlive Then Me.tUpload.Abort()
Me.tUpload =3D Nothing
'TODO log failure of upload thread...
Continue For 'Skip this file...
'Throw ex
End Try
Try 'ESTIMATE THE PROGRESS OF THE WORKER
THREAD WHILE CHECKING ITS THREADSTATE...
While Me.tsUploadStart =3D Nothing
OrElse (Me.tUpload.ThreadState And Threading.ThreadState.Unstarted) =3D
Threading.ThreadState.Unstarted
Thread.Sleep(5) 'wait for thread
to start...
End While
While (Me.tUpload.ThreadState And
Threading.ThreadState.Stopped) =3D 0
'If Me.tUpload.ThreadState And
Threading.ThreadState.WaitSleepJoin =3D
Threading.ThreadState.WaitSleepJoin Then Me.tUpload.Interrupt() 'IS
this what I need todo to get avoid the waitsleepjoin? Why did the
child thread go to sleep?
intSecs =3D ((New
TimeSpan(Now.Ticks)).TotalMilliseconds -
Me.tsUploadStart.TotalMilliseconds) / 1000.0
If bProgress Then
If Me.dblBytesPerSecond =3D 0
Then
dblProgress =3D intSecs /
(intFileSize / (0.8 * 32.768)) 'default upload speed to to 80% of
~262kbps ~=3D 32.768K/sec (typical upload speed of cable modem)
Else
dblProgress =3D intSecs /
(intFileSize / Me.dblBytesPerSecond)
End If
If dblProgress > 0.99 Then
dblProgress =3D 0.99
RaiseEvent
StatusChange(strMessage & ", " & Format(dblProgress, "0.#%") & New
String(".", intSecs Mod 11))
Else
RaiseEvent
StatusChange(strMessage & ", " & intSecs & "second(s)" & New
String(".", intSecs Mod 11))
End If
Thread.Sleep(100)
End While
If Me.strUploadResult Is Nothing Then
Debug.WriteLine("processing of
upload failed...")
RaiseEvent
StatusChange(strMessage
& " upload failed")
If Not Me.tUpload Is Nothing
AndAlso Me.tUpload.IsAlive Then Me.tUpload.Abort()
Me.tUpload =3D Nothing
'TODO log failure of upload
thread...
Continue For 'Skip this file...
'Throw ex
'Exit For 'TODO should be keep
trying to uploads?
ElseIf
InStr(Me.strUploadResult.ToUpper, "ERROR") =3D 1 Then
Debug.WriteLine(" upload failed "
& Me.strUploadResult)
RaiseEvent
StatusChange(strMessage
& " upload failed " & Replace(Me.strUploadResult, "ERROR", ""))
If Not Me.tUpload Is Nothing
AndAlso Me.tUpload.IsAlive Then Me.tUpload.Abort()
Me.tUpload =3D Nothing
'TODO log failure of upload
thread...
Continue For 'Skip this file...
'Throw ex
'Exit For 'TODO should be keep
trying to uploads?
Else
RaiseEvent
StatusChange(strMessage
& " complete")
'Calculate elapsed time, store
stats for future uploads
RaiseEvent
TrackUploadStats(intFileSize, (Me.tsUploadEnd.TotalMilliseconds -
Me.tsUploadStart.TotalMilliseconds) / 1000)
RaiseEvent
FileUploadComplete(Me.strUploadFileName, Now) 'Mark this file as
being
uploaded...
End If
Catch ex As Exception
Debug.WriteLine("processing of upload
failed..." & vbNewLine & ex.Message & vbNewLine & ex.StackTrace)
RaiseEvent StatusChange(strMessage &
"
upload failed " & ex.Message)
If Not Me.tUpload Is Nothing AndAlso
Me.tUpload.IsAlive Then Me.tUpload.Abort()
Me.tUpload =3D Nothing
'TODO log failure of upload thread...
Continue For 'Skip this file...
'Throw ex
End Try
Next i
RaiseEvent StatusChange("Upload complete...")
Thread.Sleep(2000) 'Dispaly complete message
for a couple of seconds...
RaiseEvent StatusChange("")
srReader.Dispose()
srReader =3D Nothing
dsFileList.Dispose()
dsFileList =3D Nothing
Catch ex As Exception
Debug.WriteLine(ex.Message & vbNewLine &
ex.StackTrace)
'TODO log error
RaiseEvent StatusChange("Error uploading file
list for CIID=3D" & strCI_Id & "..." & ex.Message)
Throw ex
End Try
End If
objWebService.Dispose()
objWebService =3D Nothing
Catch ex As Exception
Debug.WriteLine(ex.Message & vbNewLine &
ex.StackTrace)
'TODO log error
RaiseEvent StatusChange("Error processing upload
action for CIID=3D" & strCI_Id & "..." & ex.Message)
Throw ex
Finally
'TODO signal main thread that uploading is complete
'RaiseEvent EnableUploadAction() 'This may not be the
correct action...
'RaiseEvent ChangeUploadButtonTooltip("No cases
pending transmission") 'This may not be true
RaiseEvent Complete()
Me.bRunning =3D False
End Try
End If
End Sub
------------------------------------------------------------ ---------------=
=AD-------------------------------
Private Sub Process_UploadFile()
Try
Dim strName As String =3D
StrReverse(StrReverse(Me.strUploadFileName).Split("\")(0)).T oUpper
Dim dt As DateTime =3D Now 'initialize to today's date...
Try
dt =3D
Me.GetInterviewStartDate(Replace(Replace(strName,
"WAV", ""), ".MP3", ""))
Catch ex As Exception
End Try
Dim objWebService As New myWebServiceClass
Me.strUploadResult =3D Nothing
Me.tsUploadStart =3D New TimeSpan(Now.Ticks) 'Capture start
time
Me.strUploadResult =3D objWebService.Upload(Me.strCI_Id,
dt,
"", strName, Me.ConvertFileToBase64(Me.strUploadFileName)) 'THIS CALL
TO THE WEB SERVICE UPLOADS A FILE... IT CAN TAKE A WHILE TO RUN
Me.tsUploadEnd =3D New TimeSpan(Now.Ticks) 'Capture end
time
objWebService.Dispose()
objWebService =3D Nothing
Catch ex As Exception
Throw ex
End Try
End Sub