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.

25
demandé sur user2847598 2015-03-09 23:06:16

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));
    }
}
31
répondu Christophe 2015-03-09 21:05:22

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);

    // ...
}

[exemple en direct]

21
répondu Angew 2015-03-09 20:50:54