web-dev-qa-db-fra.com

Est-ce que C ++ std :: set thread-safe?

J'ai une question sur la sécurité des threads de std :: set.

Pour autant que je sache, je peux parcourir un ensemble et ajouter/effacer des membres et cela n'invalide pas les itérateurs.

Mais envisagez le scénario suivant:

  • le thread 'A' parcourt un ensemble de shared_ptr <Type>
  • le fil "B" ajoute occasionnellement des éléments à cet ensemble.

J'ai rencontré des erreurs de segmentation pendant l'exécution du programme et je ne sais pas pourquoi cela se produit. Le manque de sécurité du fil est-il la cause?

38
Racer

STL n'a pas de support de thread intégré, vous devrez donc étendre le code STL avec vos propres mécanismes de synchronisation pour utiliser STL dans un environnement multithread.

Par exemple, regardez ici: texte du lien

Puisque set est une classe de conteneur, MSDN a à dire sur la sécurité des threads des conteneurs.

Un objet unique est thread-safe pour la lecture à partir de plusieurs threads. Par exemple, étant donné un objet A, il est sûr de lire A à partir du thread 1 et du thread 2 simultanément.

Si un seul objet est écrit par un thread, toutes les lectures et écritures sur cet objet sur le même thread ou sur d'autres threads doivent être protégées. Par exemple, étant donné un objet A, si le thread 1 écrit dans A, alors le thread 2 doit être empêché de lire ou d'écrire dans A.

Il est sûr de lire et d'écrire dans une instance d'un type même si un autre thread lit ou écrit dans une autre instance du même type. Par exemple, étant donné les objets A et B du même type, il est sûr si A est écrit dans le thread 1 et B est lu dans le thread 2.

30
Vaibhav

La documentation Dinkumware STL contient le paragraphe suivant sur ce sujet. Son probablement (comme indiqué dans le texte) valable pour la plupart des implémentations.

Pour les objets conteneurs définis dans la bibliothèque C++ standard, tels que les conteneurs STL et les objets de la classe de modèle basic_string, cette implémentation suit les pratiques largement adoptées énoncées pour SGI STL:

Plusieurs threads peuvent lire en toute sécurité le même objet conteneur. (Il existe des sous-objets mutables non protégés dans un objet conteneur.)

Deux threads peuvent manipuler en toute sécurité différents objets conteneurs du même type. (Il n'y a pas d'objets statiques partagés non protégés dans un type de conteneur.)

Vous devez vous protéger contre l'accès simultané à un objet conteneur si au moins un thread modifie l'objet. (Les primitives de synchronisation évidentes, telles que celles de la bibliothèque de threads Dinkum, ne seront pas subverties par l'objet conteneur.)

Ainsi, aucune tentative n'est faite pour garantir que les opérations atomiques sur les objets conteneurs sont thread-safe; mais il est assez facile de créer des objets conteneurs partagés qui sont thread-safe au niveau de granularité approprié.

23
RED SOFT ADAIR

Aucun des conteneurs STL n'est thread-safe, donc std::set en particulier non.

Dans votre cas, le problème n'est même pas vraiment la sécurité des threads: vous partagez simplement un objet sur plusieurs threads (fin) et le modifiez dans un seul thread (fin aussi). Mais comme vous l'avez déjà dit, la modification du conteneur invalide ses itérateurs. Que cela se produise dans le même thread ou dans un autre thread n'a aucune conséquence car c'est toujours le même conteneur.

D'oh! Le §23.1.2.8 indique que l'insertion n'invalide pas les itérateurs.

11
Konrad Rudolph

La réalisation d'une insertion peut amener le vecteur à réallouer sa mémoire sous-jacente tandis que l'itérateur peut toujours pointer vers l'adresse mémoire précédente (mais non valide), entraînant une erreur de segment.

2
user1988707

Explication simple: si le thread A déplace les itérateurs à travers le conteneur, il regarde les internes du conteneur. Si le thread B modifie le conteneur (même une opération qui n'invalide pas l'itérateur que A possède), le thread A peut rencontrer des problèmes car B trompe les composants internes du conteneur, ce qui peut les avoir dans un état (temporairement) non valide. Cela provoque des plantages dans le thread A.

Le problème N'EST PAS les itérateurs eux-mêmes. C'est quand ils ont besoin des structures de données du conteneur afin de trouver la position que vous rencontrez des problèmes.

Aussi simple que cela.

2
Michael Kohne

Oui. Une façon de gérer cette situation consiste à avoir chaque thread verrouiller un mutex partagé avant d'accéder au même objet ensemble. Assurez-vous d'utiliser des techniques RAII pour verrouiller et déverrouiller le mutex.

1
Brian Neal