2015-03-09 18 views
24

Di seguito è solo un semplice programma per testare utilizzando due thread per inserire una tabella hash. viene utilizzato.C++: errore: nessun tipo denominato 'tipo' in 'classe std :: result_of <void (* (std :: unordered_map

#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; 
} 

Tuttavia, ci sono errori durante la compilazione di esso.

$ 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; 
... 

voluto un po ', ma ancora non è possibile correggerlo. Grazie.

+0

possibile duplicato di: http://stackoverflow.com/questions/8299545/passing-arguments-to-thread-function correlate : http://stackoverflow.com/questions/5116756/difference-between-pointer-and-reference-as-thread-parameter –

risposta

26

ho potuto compilare il codice con successo con MSVC2013. Tuttavia, thread() funziona passando copie del suo argomento al nuovo thread. Ciò significa che se il tuo codice verrà compilato sul tuo compilatore, ciascun thread verrà eseguito con la propria copia di ht, in modo che, alla fine, main 's ht sia vuoto.

GCC non viene compilato con questo messaggio strano. È possibile sbarazzarsi di esso utilizzando il wrapper di riferimento con thread:

t[0] = thread(thread_add, std::ref(ht), 0, 9); 
t[1] = thread(thread_add, std::ref(ht), 10, 19); 

Questo verrà compilato con successo. E ogni riferimento usato dai thread si riferirebbe allo stesso oggetto.

Tuttavia, è molto probabile che si verifichino errori di runtime o risultati imprevisti. Questo perché due thread stanno cercando con certezza di inserirsi in ht. Ma unordered_map non è thread-safe, quindi queste condizioni di gara potrebbero causare ht per raggiungere uno stato instabile (ad esempio UB, cioè potenziale segfault).

Per rendere più funziona correttamente, è necessario proteggere il vostro concurent accessi:

#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)); 
    } 
} 
+4

Si noti che msvc è in errore qui. – Yakk

21

l'errore è davvero molto criptico, ma la il problema è che thread_add prende il suo primo parametro per riferimento, ma lo passi per valore. Ciò causa il tipo di functor da dedurre errato. Se si desidera passare qualcosa di realmente con riferimento ad un funtore come std::bind o la funzione principale di un std::thread, è necessario utilizzare un wrapper di riferimento (std::ref):

void test() 
{ 
    // ... 

    t[0] = thread(thread_add, std::ref(ht), 0, 9); 
    t[1] = thread(thread_add, std::ref(ht), 10, 19); 

    // ... 
} 

[Live example]

+0

Btw, clang non è molto meglio (Tentativo di utilizzare una funzione cancellata), ma almeno ti porta dove è stata decomposta la tupla dei parametri, che è una cosa che immagino. – WhozCraig

+5

Non correlato, ma passando per riferimento creerà una corsa di dati su 'ht'. – Snps

+0

@Snps Ho preso la dichiarazione dell'OP di "For test no lock is used" nel senso che intendono fornire un lock quando si esegue "live". – Angew

Problemi correlati