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?
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.
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.
Les réponses existantes couvrent les points principaux:
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 ...
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:
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.