La référence à un objet dans std :: map est-elle thread-safe?
std::map< std::string, Object > _objects;
la carte peut être modifiée à partir de nombreux threads et cet accès est synchronisé, mais la référence à la valeur (Object &) est accessible uniquement à partir d'une instance et d'un thread. les opérations d'écriture avec Object sont-elles sécurisées si un autre thread ajoutera des éléments à la carte? va-t-il être réaffecté?
La norme C++ 11 garantit que l'accès de la méthode const
aux conteneurs est protégé contre différents threads (c'est-à-dire que les deux utilisent les méthodes const
).
De plus, [container.requirements.dataraces] indique
des implémentations sont nécessaires pour éviter les courses de données lorsque le contenu de l'objet contenu dans différents éléments dans la même séquence, à l'exception de
vector<bool>
En d'autres termes, à l'exception de vector<bool>
la modification de contenus distincts n'est pas une course aux données.
Maintenant, si un thread invalide un itérateur utilisé par un autre thread, il s'agit clairement d'une course aux données (et entraîne un comportement indéfini). Si un thread a un accès non - const
à un conteneur et un autre un accès const
, c'est une course aux données (et un comportement non défini). (Remarque: un certain nombre de fonctions sont "considérées const
" à des fins de multithreading, y compris begin
, end
et d'autres fonctions (et méthodes) qui ne sont pas - const
simplement parce qu'ils renvoient des itérateurs non - const
. []
est inclus dans cet ensemble de pseudo - const
pour des raisons de sécurité des threads, à l'exception de map
et unordered_set
etc - 23.2.2.1).
Cependant, il semble que si vous avez une référence à un élément dans le conteneur et que vous effectuez des opérations qui n'invalident pas cette référence dans un autre thread et que vous n'écrivez jamais dans cet élément dans un autre thread, vous pouvez lire en toute sécurité à partir de cette référence. De même, si d'autres threads ne lisent même jamais à partir de l'élément, l'écriture dans cet élément ne devrait pas entraîner de comportement indéfini.
Pour les références aux normes, 17.6.5.9.5 semble garantir que les fonctions de la bibliothèque standard ne s'exécuteront pas et liront/écriront les éléments inutilement.
Donc, la réponse courte: vous êtes en sécurité, tant que l'autre thread ne dérange pas directement cette entrée particulière dans le map
.
Les éléments d'une carte sont stables, ils ne sont ni déplacés ni invalidés à moins que l'élément ne soit effacé de la carte. Si un seul thread écrit sur un objet donné et que les modifications apportées à la carte elle-même sont correctement synchronisées, alors je crois ce sera sûr. Je suis sûr que c'est sûr dans la pratique, et je pense que c'est sûr en théorie aussi.
La norme garantit que des éléments distincts peuvent être modifiés par différents threads, dans [container.requirements.dataraces]
Nonobstant (17.6.5.9), les implémentations sont requises pour éviter les courses de données lorsque le contenu de l'objet contenu dans différents éléments dans la même séquence, à l'exception de
vector<bool>
, sont modifiés simultanément.
Cela vous permet uniquement de modifier les éléments, pas d'insérer de nouveaux éléments dans la carte lors de la modification des éléments. Pour certains conteneurs, tels que std::vector
, la modification du vecteur lui-même peut également modifier des éléments en les réaffectant et en les déplaçant, mais [associative.reqmts]/9 assure std::map
n'invalidera pas les éléments existants.
Puisqu'aucune fonction membre de std::map
est requis pour accéder au deuxième membre de ses éléments (c'est-à-dire mapped_type
) Je pense que [res.on.data.races]/5 dit qu'aucun autre thread n'entrera en conflit avec les écritures de ce membre lors de la modification de la carte. (Merci à Yakk pour cette dernière pièce du puzzle)