2009-11-18 8 views
0

J'ai écrit le code suivant pour effectuer une publication HTTP simultanée et archivage de fichiers:Est-ce que ce code d'enfilage fait ce que je pense qu'il est?

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() 

J'ai deux fils (1 & 2) la lecture d'une file d'attente de messages XML et l'affichage des messages via HTTP à un serveur Web . Une fois qu'un message est publié, il est retiré de cette file d'attente ajoutée à une deuxième file d'attente. Thread 3 lit cette file d'attente et écrit simplement le code XML dans un fichier.

Je m'attendrais à voir les fichiers XML apparaître progressivement comme des threads 1 & 2 traiter la file d'attente de messages (parfois la file d'attente de messages peut prendre environ 40 minutes à traiter). Ce que je vois réellement, c'est qu'aucun fichier XML n'apparaît. J'ai mal compris le code?

* Modifier. Voici le code pour les quatre méthodes filetées pertinentes:

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 
+1

Vous devrez afficher le code des fonctions 'ProcessNTSMessageQueue' et' ProcessSuccessfulNTSMessageQueue'. –

+0

Merci à tous pour l'aide, c'est ma première incursion dans le filetage et je ne suis pas vraiment sûr de ce que je fais à ce stade! – Simon

Répondre

3

Cette section ProcessSuccessfulNTSMessageQueue sort de la méthode (et se termine le fil) pour la première fois à travers, car il n'y a probablement pas de messages sur la file d'attente lorsque le fil commence:

If _SentMessageQueue.Count > 0 Then 
    msg = _SentMessageQueue.Dequeue() 
Else 
    Exit Sub 
End If 

La question est , comment pouvez-vous savoir quand le troisième thread est fait, non? La solution consiste à faire une autre variable de niveau classe à signaler lorsque les deux premiers threads sont terminés. Dans ProcessNTSMessageQueue, vous devez créer ici:

If _MessageQueue.Count > 0 Then 
    msg = _MessageQueue.Dequeue() 
Else 
    _IsStartQueueEmpty = True; 
    Exit Sub 
End If 

Et ProcessSuccessfulNTSMessageQueue, vous utiliseriez comme ceci:

If _SentMessageQueue.Count > 0 Then 
    msg = _SentMessageQueue.Dequeue() 
Else 
    If _IsStartQueueEmpty Then 
     Exit Sub 
End If 
+0

Je dirais que c'est ce qui se passe –

+0

Devrait probablement continuer (ou équivalent VB) –

+0

cela fonctionne exactement comme je le voulais. Merci beaucoup. – Simon

0

Non, vous ne comprenez pas le code; pour moi, il semble qu'il y ait un bug dans l'une de vos fonctions (ou ProcessNTSMessageQueue n'est pas écrit d'une manière thread-safe et, par conséquent, ne peut pas être parallélisé).

Avez-vous essayé de faire évoluer votre code dans Visual Studio? Vous pouvez appuyer sur le bouton Pause, puis sélectionner un fil dans la liste déroulante de la barre d'outils.

2

Si le code de ProcessNTSMessageQueue et ProcessSuccessfulNTSMessageQueue est correct, vous devriez voir les résultats attendus.

choses à vérifier:

  • Est-ce votre threadsafe de file d'attente?
  • Comment dépréciez-vous objcts?
  • Comment le thread de lecture est-il averti des nouvelles écritures dans la file d'attente?
+0

hmm, votre troisième point est intéressant - je ne suis pas sûr si elle est notifiée. – Simon

2

Je suis d'accord avec sternale à @ Jeff problème probable, à savoir que Le ProcessSuccessfulNTSMessageQueue() quitte tôt. Au-delà de cela, il semble que vous ayez une condition de concurrence concernant la variable _SentMessageQueue. Dans PostSuccessfulNTSMessageQueue(), vous verrouillez la file d'attente. Mais il semble que la file d'attente soit créée dans la méthode PostXMLToNTS(). Si tel est le cas, vous courez le risque que l'instruction lock dans ProcessSuccessfulNTSMessageQueue() lève un ArgumentNullException si la file d'attente n'a pas encore été créée.

En outre, vous ne synchronisez aucune opération Enqueue() dans la méthode PostXMLToNTS(). Ceux-ci doivent être synchronisés comme l'opération Dequeue() est dans la méthode ProcessSuccessfulNTSMessageQueue().

+0

Bons résultats - J'étais trop concentré sur la question principale. Ceux-ci devront être corrigés aussi. –