web-dev-qa-db-fra.com

c ++: erreur: aucun type nommé ‘type’ dans ‘class std :: result_of <void (* (std :: unordered_map

Voici un simple programme pour tester en utilisant deux threads pour insérer une table de hachage. Pour le test, 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 sa 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;
...

Cela a pris du temps mais je ne peux toujours pas le corriger. Merci.

28
user2847598

J'ai pu compiler votre code avec succès avec MSVC2013. Cependant, thread() 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, le main de ht serait vide.

GCC ne compile pas avec ce message étrange. Vous pouvez vous en débarrasser en utilisant le wrapper 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 se compilera avec succès. Et chaque référence utilisée par les threads ferait référence au même objet.

Cependant, il y a de fortes chances que vous obteniez une erreur d'exécution ou des résultats inattendus. Cela est dû au fait que deux threads essaient simultanément d'insérer dans ht. Mais unordered_map n'est pas sûr pour les threads, donc ces conditions de course peuvent faire que ht atteigne un état instable (c'est-à-dire UB, c'est-à-dire un défaut de segmentation potentiel).

Pour le faire fonctionner correctement, vous devez protéger vos accès simultanés:

#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));
    }
}
35
Christophe

L'erreur est vraiment très cryptique, mais le problème est que thread_add prend son premier paramètre par référence, mais vous le transmettez par valeur. Cela entraîne une déduction incorrecte du type de foncteur. Si vous voulez passer quelque chose en fait en 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]

22
Angew