Puis-je accéder à une entrée C ++ 11 std :: map tout en insérant / effaçant un autre thread?

Puis-je accéder (sans verrouiller) une entrée std :: map pendant qu’un autre thread insère / efface des entrées?

exemple pseudo C ++:

typedef struct { int value; int stuff; }some_type_t; std::map my_map; //thread 1 does: my_map.at('a')->value = 1; //thread 2 does: some_type_t* stuff = my_map.at('b'); //thread 3 does: my_map.erase('c'); //I'm not modifying any elements T is a pointer to an previously allocated "some_type_t" 

std C ++ 11 dit que tous les membres doivent être thread-safe (erase () n’est pas const).

Non non Non Non Non!

map::erase modifie les liens entre les entrées de la carte et qui dérange avec l’algorithme de recherche utilisé dans map::at . Vous pouvez utiliser les éléments lors d’un effacement, mais vous ne pouvez pas exécuter l’algorithme de recherche lui-même!

J’ai créé un programme d’illustration. Sur mon ordinateur, ce programme imprime parfois correctement et génère parfois une exception de carte, ce qui signifie que la recherche a mal tourné. L’augmentation du nombre de threads de lecture fait apparaître l’exception plus souvent.

 #include  #include  #include  #include  std::map m; // this thread uses map::at to access elements void foo() { for (int i = 0; i < 1000000; ++i) { int lindex = 10000 + i % 1000; int l = m.at(lindex); assert(l == lindex); int hindex = 90000 + i % 1000; int h = m.at(hindex); assert(h == hindex); } std::cout << "OK" << std::endl; } // this thread uses map::erase to delete elements void bar() { for (int i = 20000; i < 80000; ++i) { m.erase(i); } } int main() { for (int i = 0; i < 100000; ++i) { m[i] = i; } std::thread read1(foo); std::thread read2(foo); std::thread erase(bar); read1.join(); read2.join(); erase.join(); return 0; } 

Non et oui.

Deux ou plusieurs threads peuvent effectuer des opérations const sur une carte, où quelques opérations non const comptent également (les opérations qui renvoient des iterators non const , ne sont donc pas const , comme begin et des commandes similaires).

Vous pouvez également modifier le composant non-clé d’un élément d’une map ou d’un set pendant que d’autres opérations qui ne lisent / écrivent / détruisent pas le composant non-clé de cet élément sont exécutées (ce qui correspond à la plupart d’entre elles, à l’exception de erase ou = ).

Vous ne pouvez pas erase insert ou effectuer d’autres opérations de carte non const similaires en effectuant quoi que ce soit avec des opérations de carte const et similaires (comme find ou at ). Notez que [] peut être similaire à erase si l’élément est ajouté.

La norme contient une liste explicite d’opérations non const qui comptent comme const aux fins de la sécurité des threads – mais il s’agit essentiellement de recherches qui renvoient un iterator ou & .

No. std :: map ne sont pas thread-safe. La bibliothèque de blocs de construction de thread (Tbb) d’Intel contient des conteneurs concurrents. Vérifier tbb

Tant que les threads n’accèdent pas à la même adresse en même temps, il n’y aura pas de problème.

Mais pour une réponse directe à votre question, non, il n’est pas thread-safe, vous ne pouvez donc pas le faire sans verrouiller sans erreur.