c++: erreur: aucun type nommé "type" dans " la classe std::résultat de
Voici juste un programme simple pour tester en utilisant deux threads pour insérer une table de hachage. Pour l'essai, aucun verrou n'est utilisé.
#include <iostream>
#include <unordered_map>
#include <thread>
using namespace std;
void thread_add(unordered_map<int, int>& ht, int from, int to)
{
for(int i = from; i <= to; ++i)
ht.insert(unordered_map<int, int>::value_type(i, 0));
}
void test()
{
unordered_map<int, int> ht;
thread t[2];
t[0] = thread(thread_add, ht, 0, 9);
t[1] = thread(thread_add, ht, 10, 19);
t[0].join();
t[1].join();
std::cout << "size: " << ht.size() << std::endl;
}
int main()
{
test();
return 0;
}
Cependant, il y a des erreurs lors de la compilation.
$ g++ -std=c++11 -pthread test.cpp
...
/usr/include/c++/4.8.2/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<void (*(std::unordered_map<int, int>, int, int))(std::unordered_map<int, int>&, int, int)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
...
A pris un certain temps mais ne peut toujours pas le corriger. Grâce.
2 réponses
Je pourrais compiler votre code avec succès avec MSVC2013. Cependant, {[2] } fonctionne en passant des copies de son argument au nouveau thread. Cela signifie que si votre code compilait sur votre compilateur, chaque thread s'exécuterait avec sa propre copie de ht
, de sorte qu'à la fin, main
{[3] } serait vide.
GCC ne compile pas avec ce message étrange. Vous pouvez vous en débarrasser en utilisant le wraper de référence avec thread:
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
Cela compilera avec succès. Et chaque référence utilisée par les threads se référeraient au même objet.
Cependant, il y a de fortes chances que vous obteniez une erreur d'exécution ou des résultats inattendus. C'est parce que deux threads essaient de manière cohérente d'insérer dans ht
. Mais unordered_map
n'est pas thread safe, donc ces conditions de course pourraient amener ht
à atteindre un état instable (c'est-à-dire UB, c'est-à-dire segfault potentiel).
Pour le faire fonctionner correctement, vous devez protéger vos accès concur:
#include <mutex>
...
mutex mtx; // to protect against concurent access
void thread_add(unordered_map<int, int>& ht, int from, int to)
{
for (int i = from; i <= to; ++i) {
std::lock_guard<std::mutex> lck(mtx); // protect statements until end of block agains concurent access
ht.insert(unordered_map<int, int>::value_type(i, 0));
}
}
L'erreur est en effet très cryptique, mais le problème est que thread_add
prend son premier paramètre par référence, mais vous le passez par valeur. Cela provoque le type de foncteur à déduire mal. Si vous voulez passer quelque chose fait par référence à un foncteur comme std::bind
ou la fonction principale d'un std::thread
, vous devez utiliser un wrapper de référence (std::ref
):
void test()
{
// ...
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
// ...
}