这个线程代码是否按照我的想法行事?

时间:2009-11-18 15:29:01

标签: .net multithreading

我编写了以下代码来执行一些同步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

4 个答案:

答案 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中单步执行代码?您可以点击暂停按钮,然后从工具栏的下拉列表中选择一个线程。