我编写了以下代码来执行一些同步HTTP发布和文件存档:
Dim t1 As New Threading.Thread(New Threading.ThreadStart(AddressOf ProcessNTSMessageQueue))
Dim t2 As New Threading.Thread(New Threading.ThreadStart(AddressOf ProcessNTSMessageQueue))
Dim t3 As New Threading.Thread(New Threading.ThreadStart(AddressOf ProcessSuccessfulNTSMessageQueue))
t1.Start()
t2.Start()
t3.Start()
t1.Join()
t2.Join()
t3.Join()
我有两个线程(1& 2)读取XML消息队列并通过HTTP将消息发布到Web服务器。发布消息后,它会从添加到第二个队列的此队列中出列。线程3读取此队列并简单地将XML写入文件。
我希望看到XML文件逐渐显示为线程1& 2处理消息队列(有时消息队列可能需要大约40分钟来处理)。我实际看到的是没有XML文件出现。我是在误解代码?
*编辑。这是四个相关的线程方法的代码:
Private Sub ProcessNTSMessageQueue()
While True
Dim msg As String = Nothing
SyncLock _MessageQueue
If _MessageQueue.Count > 0 Then
msg = _MessageQueue.Dequeue()
Else
Exit Sub
End If
End SyncLock
'Post the message
'it's important to do this outside lock()
If msg <> Nothing Then
Me.PostXMLToNTS(msg)
End If
End While
End Sub
Private Sub ProcessSuccessfulNTSMessageQueue()
While True
Dim msg As String = Nothing
SyncLock _SentMessageQueue
If _SentMessageQueue.Count > 0 Then
msg = _SentMessageQueue.Dequeue()
Else
Exit Sub
End If
End SyncLock
'Post the message
'it's important to do this outside lock()
If msg <> Nothing Then
Me.ArchiveXMLAsFile(Guid.NewGuid.ToString, msg)
_SuccessfulMessageCount += 1
End If
End While
End Sub
Private Function PostXMLToNTS(ByVal XMLString As String) As Boolean
Try
Dim result As Net.HttpStatusCode = NTSPoster.PostXml(XMLString, _Settings.NTSPostURLCurrent, _Settings.NTSPostUsernameCurrent, _Settings.NTSPostPasswordCurrent)
Select Case result
Case Net.HttpStatusCode.Accepted, Net.HttpStatusCode.OK 'Good
If _SentMessageQueue Is Nothing Then
_SentMessageQueue = New Queue(Of String)
End If
_SentMessageQueue.Enqueue(XMLString)
Return True
Case Else 'Probably bad
If _FailedMessageQueue Is Nothing Then
_FailedMessageQueue = New Queue(Of String)
End If
_FailedMessageQueue.Enqueue(XMLString)
Return False
End Select
Catch ex As Exception
Throw
End Try
End Function
Private Sub ArchiveXMLAsFile(ByVal name As String, ByVal XML As String)
Try
'Create directory in archive location based on todays date
Dim dir As New DirectoryInfo(Me.TodaysXMLArchiveLocation)
'If the directory does not already exist then create it
If Not dir.Exists Then
dir.Create()
End If
Dim FileName As String = String.Format("{0}.xml", name)
Using sw As StreamWriter = New StreamWriter(Path.Combine(dir.FullName, FileName))
sw.Write(XML)
sw.Close()
End Using
Catch ex As Exception
Throw
End Try
End Sub
答案 0 :(得分:3)
ProcessSuccessfulNTSMessageQueue
的这一部分在第一次退出方法(并终止线程),因为线程开始时队列中可能没有任何消息:
If _SentMessageQueue.Count > 0 Then
msg = _SentMessageQueue.Dequeue()
Else
Exit Sub
End If
问题是,你怎么知道第三个线程何时完成,对吧?解决方案是使另一个类级变量在前两个线程完成时发出信号。在ProcessNTSMessageQueue
中,您可以在此设置:
If _MessageQueue.Count > 0 Then
msg = _MessageQueue.Dequeue()
Else
_IsStartQueueEmpty = True;
Exit Sub
End If
在ProcessSuccessfulNTSMessageQueue
中,您可以像这样使用它:
If _SentMessageQueue.Count > 0 Then
msg = _SentMessageQueue.Dequeue()
Else
If _IsStartQueueEmpty Then
Exit Sub
End If
答案 1 :(得分:2)
如果ProcessNTSMessageQueue和ProcessSuccessfulNTSMessageQueue的代码是正确的,您应该会看到预期的结果。
要检查的事项:
答案 2 :(得分:2)
我同意@Jeff Sternal关于可能存在的问题,即ProcessSuccessfulNTSMessageQueue()
提前退出。
除此之外,看起来你有_SentMessageQueue
变量的竞争条件。在PostSuccessfulNTSMessageQueue()
中,您可以锁定队列。但看起来PostXMLToNTS()
方法中的队列是创建的。如果是这种情况,那么如果尚未创建队列,那么您将面临lock
中的ProcessSuccessfulNTSMessageQueue()
语句将抛出ArgumentNullException
的风险。
此外,您没有在Enqueue()
方法中同步PostXMLToNTS()
操作。这些需要像Dequeue()
方法中的ProcessSuccessfulNTSMessageQueue()
操作一样进行同步。
答案 3 :(得分:0)
不,你不会误解代码;对我来说,看起来你的一个函数中存在一个错误(或ProcessNTSMessageQueue
不是以线程安全的方式编写的,因此无法并行化。)
您是否尝试在Visual Studio中单步执行代码?您可以点击暂停按钮,然后从工具栏的下拉列表中选择一个线程。