web-dev-qa-db-fra.com

unordered_map thread safety

Je change un programme à thread unique en multi thread à l'aide de la bibliothèque boost: thread. Le programme utilise unordered_map comme hasp_map pour les recherches. Ma question est.. 

À un moment donné, de nombreux fils vont écrire, et à un autre moment, beaucoup vont lire, mais pas à la fois lire et écrire en même temps, c’est-à-dire que tous les fils vont lire ou tous vont écrire. Sera-ce thread safe et le conteneur conçu pour cela? Et si ce sera le cas, sera-t-il vraiment concurrent et améliorera-t-il les performances? Dois-je utiliser un mécanisme de verrouillage?

J'ai lu quelque part que la norme C++ dit que le comportement ne sera pas défini, mais est-ce tout?

UPDATE: Je pensais aussi à Intel concurrent_hash_map. Sera-ce une bonne option?

20
questions

Les conteneurs STL sont conçus pour que vous puissiez avoir:

A. Plusieurs threads lisant en même temps

ou

B. Un fil écrit à la fois

L'écriture de plusieurs threads n'est pas l'une des conditions ci-dessus et n'est pas autorisée. L'écriture de plusieurs threads va donc créer une course de données, qui est un comportement indéfini.

Vous pouvez utiliser un mutex pour résoudre ce problème. Un shared_mutex (associé à shared_locks) serait particulièrement utile car ce type de mutex autorise plusieurs lecteurs simultanés.

http://eel.is/c++draft/res.on.data.races#3 est la partie de la norme qui garantit la possibilité d'utiliser simultanément des fonctions const sur différents threads. http://eel.is/c++draft/container.requirements.dataraces spécifie quelques opérations non constantes supplémentaires qui sont sécurisées sur différents threads.

40
Lalaland

Sera-ce thread safe et le conteneur conçu pour cela?

Non, les conteneurs standard ne sont pas thread thread.

Dois-je utiliser un mécanisme de verrouillage?

Oui vous Puisque vous utilisez boost, boost::mutex serait une bonne idée; en C++ 11, il y a std::mutex.

J'ai lu quelque part que la norme C++ dit que le comportement ne sera pas défini, mais est-ce tout?

En effet, le comportement n'est pas défini. Je ne suis pas sûr de comprendre ce que vous entendez par "est-ce tout?", Car un comportement non défini est le pire type de comportement possible, et un programme qui le présente est par définition incorrect. En particulier, une synchronisation de threads incorrecte risque de provoquer des plantages aléatoires et une corruption des données, souvent de manière très difficile à diagnostiquer. Il serait donc sage de l'éviter à tout prix.

UPDATE: Je pensais aussi à Intel concurrent_hash_map. Sera-ce une bonne option?

Ça a l'air bien, mais je ne l'ai jamais utilisé moi-même, je ne peux donc pas donner d'avis.

7
Mike Seymour

Les réponses existantes couvrent les points principaux:

  • vous devez avoir un verrou pour lire ou écrire sur la carte
  • vous pouvez utiliser un verrou à plusieurs lecteurs/un seul rédacteur pour améliorer la concurrence

En outre, vous devez savoir que:

  • l'utilisation d'un itérateur récupéré précédemment, d'une référence ou d'un pointeur sur un élément de la carte compte comme une opération de lecture ou d'écriture

  • les opérations d'écriture effectuées dans d'autres threads peuvent invalider les pointeurs/références/itérateurs de la carte, comme ils le feraient s'ils étaient exécutés dans le même thread, même si un verrou est à nouveau acquis avant de tenter de continuer à les utiliser ...

3
Tony Delroy

std :: unordered_map remplit les conditions de Container (ref http://fr.cppreference.com/w/cpp/container/unordered_map ). Pour la sécurité des threads de conteneur, voir: http://fr.cppreference.com/w/cpp/container#Thread_safety .

Les points importants:

  • "Différents éléments d'un même conteneur peuvent être modifiés simultanément par différents threads"
  • "Toutes les fonctions membres const peuvent être appelées simultanément par différents threads sur le même conteneur. En outre, les fonctions membres begin (), end (), rbegin (), rend (), front (), back (), data () , find (), lower_bound (), upper_bound (), equal_range (), at () et, sauf dans les conteneurs associatifs, operator [], se comporte comme const aux fins de la sécurité du thread (en d'autres termes, ils peuvent également être appelés simultanément par différents threads sur le même conteneur). "
1
Ida

Vous pouvez utiliser concurrent_hash_map ou utiliser un mutex lorsque vous accédez à unordered_map. L’un des problèmes concernant l’utilisation d’intel concurrent_hash_map est qu’il faut inclure TBB, mais vous utilisez déjà boost.thread Ces deux composants ont des fonctionnalités qui se chevauchent et compliquent donc votre base de code.

1
Chang