12
votes

Une liste peut-elle être accessible par plusieurs threads?

Je prévois de partager une liste entre plusieurs threads. La liste sera verrouillée lors d'une modification, qui arrive rarement. Existe-t-il un problème de sécurité de thread si plusieurs itérations sont fabriquées à partir de threads différents via la liste simultanément?


2 commentaires

Si la liste est verrouillée correctement, quelle sorte de problème pourrait-il être?


Vous ne pouvez pas verrouiller une liste, vous pouvez uniquement bloquer le code. Demandez à tous les codes qui accède à la liste (ou à ses objets d'élément) entrez une instruction de verrouillage utilisant un objet privé pour garder l'état de verrouillage.


5 Réponses :


13
votes

Si vous le pouvez (si vous pouvez utiliser .NET 4 c'est), utilisez blocageCollection :

fournit des capacités de blocage et de liaison pour les collections de fil-sécurité qui implémentent iproducerconsumercollection .

Sinon, sinon encapsule complètement la liste et ajoutez des méthodes de fil-sécurité qui accèdent à la liste Liste 's . Ne faites pas référence à la liste publique ou renvoyez-la à partir de toutes méthodes - encapsulez toujours la référence afin que vous puissiez garantir que vous vous classez autour de tout accès.


4 commentaires

Y a-t-il un coût pour utiliser BlockingCollection ?


@Behroz: Plus de coûts qu'un wrapper personnalisé autour de la liste qui implémente la même logique de verrouillage. S'agissant exactement comment beaucoup surhead il ajoute plus sur liste je ne peux pas dire.


Je suis surpris que cette réponse soit acceptée. Le comportement par défaut de blocageCollection est une file d'attente plutôt qu'une liste. Il n'y a aucun moyen d'y accéder par index et il n'y a aucun moyen de le faire itérer sans éliminer les articles. Je suppose que l'OP avait vraiment besoin d'une file d'attente.


Queue d'identification par défaut, mais vous pouvez le remplacer par tout ce que vous voulez.



8
votes

a Liste N'est-ce pas une classe de fil-sécurité, mais si vous vous verrouillez chaque fois que vous lisez / écrivez-y, il n'y aura pas de problèmes. Selon la documentation:

Statique publique (partagée dans Visual Basic) Les membres de ce type sont le fil sûr. N'importe quel cas ne sont pas Garanti d'être le fil sûr.

A Liste peut prendre en charge plusieurs lecteurs simultanément, aussi longtemps que la la collecte n'est pas modifiée. Énumérer à travers une collection est intrinsèquement pas un coffre-fort procédure. Dans le cas rare où un L'énumération soutient avec un ou plusieurs accès écrit, le seul moyen de s'assurer La sécurité du fil est de verrouiller la Collection pendant toute la énumération. Permettre la collection à accéder par plusieurs threads pour lecture et écriture, vous devez Mettre en œuvre votre propre synchronisation.


0 commentaires

2
votes

Il peut être lire à partir de plusieurs threads simultanément, si c'est ce que vous demandez. Considérons une serrure auteur de lecteur si oui.


0 commentaires

6
votes

Liste n'est pas le fil de sécurité en général. Avoir plusieurs lecteurs ne causera aucun problème, cependant, vous ne pouvez pas écrire à la liste pendant qu'il est lu. Donc, vous auriez besoin de verrouiller à la fois lire et écrire ou utiliser quelque chose comme un System.Threading.readerwriterlock (qui permet plusieurs lecteurs mais un seul écrivain).


2 commentaires

Il n'ya presque jamais de cas pour préférer ReaderWriterLock sur ReaderWriterLockSlim . La version SLIM fonctionne mieux et a une API bien meilleure.


TRUE, mais ReaderWriterLocksLim est uniquement disponible en v3.5 + comme dans System.core.dll . ReaderWriterLock est disponible auprès de V1.1 + et se trouve dans le MSCORLIB . Malheureusement, je suis obligé de travailler avec beaucoup de code .net 2.0, donc je n'ai donc aucun choix dans la matière.



0
votes

Pour répondre à cette question, vous devez d'abord jeter un coup d'œil à la documentation, puis sur le code source et il y a un avertissement à cet endroit - le code source de liste peut être modifié au cours des années.

Darin Dimitrov a cité la documentation de l'année 2010 et il y a des différences pour l'année 2021:

Les membres publiques statiques (partagés dans Visual Basic) de ce type sont du thread en sécurité. Tous les membres de l'instance ne sont pas garantis pour être en sécurité.

Il est prudent d'effectuer plusieurs opérations de lecture sur une liste, mais Les problèmes peuvent se produire si la collection est modifiée alors qu'elle est en cours de lecture. Pour assurer la sécurité du fil, verrouillez la collection pendant une lecture ou une écriture opération. Pour permettre une collection d'être accessible par plusieurs threads Pour la lecture et l'écriture, vous devez mettre en œuvre votre propre synchronisation. Pour les collections avec synchronisation intégrée, voir les classes de la System.Collections. Espace de nomsCurrent. Pour un coffre-fort intrinsèquement Alternative, voir la classe d'immutablelist.

Comme vous pouvez le constater, il n'y a déjà pas une telle phrase

énumérer à travers une collection n'est intrinsèquement pas un coffre-fort Procédure

Donc, un conseil est - vérifier le documentation et Mise en œuvre de Liste et suivre les modifications sur .NET Framework .

La réponse à votre question est - cela dépend .

Si vous utilisez foreach à itérer via la liste, si la liste a été modifiée, même appelez simplement la liste [i] = valeur , dans laquelle la valeur est égal à la liste [i] , vous deviendrez une exception, car la liste ._ version (qui sera vérifiée par l'objet Enumerator) être changé sur ensemble.

pour La boucle de cet endroit ne jettera pas une exception, si vous modifiez une valeur dans la liste, mais la modification de la longueur de la liste peut être dangereuse.

si la liste ne sera pas modifiée du tout pendant l'itération , alors l'itération est le fil sûr.


5 commentaires

Je crois que la raison pour laquelle ils ont supprimé le "énumérer à travers une collection ne sont intrinsèquement pas une procédure de fil-sécurité" la déclaration est parce qu'elle est réfutée par la simple existence des collections immuables. Rien n'a effectivement changé avec la liste Tapez elle-même, depuis le Darin Dimitrov's 2010 Réponse .


@Theodorzoulias Recherche dans la mise en œuvre de BinarinCompatibilittibilité.TaretsatLeast_desktop_v4_5


Ceci suggère que la méthode foreach était incompatible avec la norme envahir énumération avant .NET 4.5, et ils l'ont réparé en rendant le foreach se comporter exactement comme le foreach . Le foreach est resté le même. BTW Il est assez facile d'énumérer une liste sans le chèque _version , si c'est ce que vous voulez: foreach (Var Article en énumérable.Range (0 , list.compt) .Sélectionnez (i => liste [i])) {... . Mais cela ne rend pas le fil de recensement. Cela ne fait que la version-agnostique.


Je voulais juste dire qu'il y avait des changements et qu'ils peuvent survenir à l'avenir, donc un conseil pour inspecter la mise en œuvre.


Rekshino Inspection Le code source peut certainement fournir des informations sur les intentions des développeurs. Mais prévoir les changements pouvant survenir à l'avenir est un étirement. Mon avis est que nous ne devrions pas nous attendre à des modifications majeures de la fonctionnalité principale et des caractéristiques d'un composant aussi populaire, comme la liste au cours des 100 prochaines années. Microsoft a montré qu'il est très conservateur lorsqu'il s'agit de préserver la compatibilité rédaction des API existantes, en particulier lorsqu'ils sont connus pour être largement utilisés.