9
votes

Queue .Dequeur retourne null

J'ai un scénario où

  • Plusieurs threads poussent des données sur une file d'attente

  • Un seul thread est le traitement des données à l'aide de code ci-dessous

    code - xxx

    mais parfois, la file d'attente.Dequeue () renvoie null dans le scénario ci-dessus Ce qui donne?


0 commentaires

7 Réponses :


2
votes

Assurez-vous que rien ne pousse null dans la file d'attente. null s sont autorisés comme des valeurs en file d'attente. Aussi, selon Ce document , uniquement Queue Les membres statiques de S sont le fil-coffre-fort, alors méfiez-vous de faire la lecture et l'écriture à travers les threads.


4 commentaires

Vous êtes mal compris que le document. Il disant que seuls les membres statiques de la file d'attente sont garantis pour être en sécurité. L'attribution d'une file d'attente à une variable statique ne le rend pas magiquement à fil-sûr.


Il n'y a pas de nulls étant poussé dans


Suivi sur le commentaire de Slaks: Queue n'a pas de membres statiques. Ce bit de la documentation est une casserole non pertinente (pour la version actuelle de la classe, au moins - les versions des cadres 2.0 et 3.0 ont chacune une méthode statique, Références ).


Merci, @slaks et @jeff. Cela donne beaucoup plus de sens.



8
votes

Vous devez synchroniser l'accès à la file d'attente. Mettez verrouillage sur toutes les sections de code qui accèdent à la file d'attente (lecture et écriture). Si vous accédez à la file d'attente simultanée à partir de plusieurs threads, les structures internes peuvent être corrompues et à peu près tout peut arriver.


5 commentaires

Si "Accès" signifie lire, il n'y a que 1 lecteur de repos (2) sont des écrivains


@Kumar: Avoir deux écrivains (sur des threads distincts) Ajouter à une collection qui n'est pas intrinsèquement thread-coffre-fort va causer des problèmes. Le droit de Guffa; Vous devez synchroniser l'accès. Voir ma réponse pour une sorte d'explication occasionnelle.


Hmm ... Seriez-vous en mesure d'utiliser un java.util.concurrent.synchronousqueue au lieu des relevés de verrouillage? Je n'ai pas encore traité cette classe.


Si vous utilisez .NET 4, vous pouvez éviter de verrouiller en utilisant le type ConcurrentQueue: CODETHinked.com/post/2010/02/04/...


Notez que dans ce scénario, une serrure exclusive a du sens. Si le scénario était de nombreux lecteurs, un écrivain, au lieu de l'inverse, alors une lectureWriterLockslim serait une meilleure solution.



10
votes

Vous devez lire Ce blog post .

En outre, voici un squelette très minime d'un" canal "pour la communication entre les threads: xxx


2 commentaires

Semble intéressant mais je préférerais utiliser le verrouillage de manière minimale, peut-être du temps pour enfin passer à travers la bibliothèque PowerTheading en détail


Si vous souhaitez utiliser un conteneur standard à partir de plusieurs threads, le code ci-dessus est minimal! Mais le powerTheading vaut la peine de regarder quand même.



0
votes

Pourquoi ne résolvez-vous pas le problème de cette façon? XXX

MISE À JOUR

OK, après avoir lu des commentaires sur les écarts et toutes les autres réponses, vous allez bien et Je suis juste faux. Donc s'il vous plaît n'utilisez pas le code ci-dessus dans des contextes multithreads .


1 commentaires

Étant donné que la méthode DEQUEUE de la file d'attente n'est pas la sécurité du fil. Si un lecteur tente de le faire en même temps qu'un écrivain tente d'insérer quelque chose, les résultats seront ... imprévisibles.



8
votes

Vous dites:

Les threads multiples poussent des données sur une file d'attente

La file d'attente .NEnqueue n'est pas du thread-coffre-fort. Cela signifie que le travail est effectué dans la méthode Enqueue qui doit être synchronisée si plusieurs threads l'appellent. Un exemple simple serait la mise à jour de la propriété compteur . C'est un pari sûr que quelque part dans la méthode Enqueue Il y a une ligne qui ressemble à ceci comme ceci: xxx

mais comme nous savons tous que ce n'est pas t une opération atomique. C'est vraiment plus comme ça (en termes de ce qui est effectivement se passe ): xxx

alors dites que le compte est actuellement 5 et thread 1 devient passé int NewCount = comptage + 1 ... puis thread 1 pense: "OK, le compte est maintenant 5, donc je vais le faire 6." Mais la prochaine opération suivante qui est exécutée est l'endroit où le thread 2 devient int NewCount = comptage + 1 et pense la même chose que le fil 1 ("Le comte est maintenant de 6"). Donc, deux éléments viennent d'être ajoutés à la file d'attente, mais le comte n'est allé que de 5 à 6.

Ceci est juste un exemple très fondamental de la manière dont une méthode non thread-sûre comme la queue .NEnqueue peut être gâché lorsque l'accès n'est pas synchronisé. Cela n'explique pas spécifiquement ce qui se passe dans votre question; Mon intention est simplement de souligner que ce que vous faites n'est pas du thread-sûr et causera un comportement inattendu .


0 commentaires

6
votes

GUFFA est correct, ayant de multiples threads Lecture et écriture à la file d'attente entraînera des problèmes, car la file d'attente n'est pas une sécurité de fil.

Si vous êtes sur .NET 4, utilisez le Concurrentqueur classe, qui est en sécurité. Si vous n'êtes pas sur .NET 3 ou plus tôt, vous pouvez faire votre propre verrouillage, car GUFFA a souligné ou utilisez une bibliothèque 3ème partie.


2 commentaires

Concurrentqueue semble très bon, tout port de cette classe dans .NET 3.5 monde?


Oui, il y a un port de Microsoft. Il est à l'intérieur de la structure Rx pour .NET 3.5: MSDN.MicRosoft.com/fr- US / DEVLABS / EE794896.ASPX



0
votes

Si vous utilisez une file d'attente non générique (non que je conseille de l'utiliser), vous pouvez utiliser la méthode de la file d'attente.Synchronisée pour obtenir un wrapper à fil-coffre-fort:

Queue queue = Queue.Synchronized(new Queue());


0 commentaires