C++: ошибка: нет типа с именем 'type' в классе '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;
}
Однако при его компиляции возникают ошибки.
$ 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;
...
Потребовалось время, но все еще не могу исправить это. Благодарю.
2 ответа
Я мог бы успешно скомпилировать ваш код с MSVC2013. Тем не мение, thread()
работает, передавая копии своего аргумента в новый поток. Это означает, что если ваш код будет компилироваться на вашем компиляторе, каждый поток будет работать со своей собственной копией ht
так что в конце main
"s ht
будет пустым.
GCC не компилирует это странное сообщение. Вы можете избавиться от него, используя справочную оболочку с потоком:
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
Это будет успешно скомпилировано. И каждая ссылка, используемая потоками, будет ссылаться на один и тот же объект.
Однако высока вероятность того, что вы получите ошибку во время выполнения или неожиданные результаты. Это потому, что два потока одновременно пытаются вставить в ht
, Но unordered_map
не является безопасным для нитей ht
достичь нестабильного состояния (то есть UB, то есть потенциального segfault).
Чтобы он работал правильно, вы должны защитить свой параллельный доступ:
#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));
}
}
Ошибка действительно очень загадочная, но проблема в том, что thread_add
принимает первый параметр по ссылке, но вы передаете его по значению. Это приводит к неправильному выводу типа функтора. Если вы хотите передать что-то на самом деле по ссылке на функтор, как std::bind
или основная функция std::thread
, вам нужно использовать справочную оболочку (std::ref
):
void test()
{
// ...
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
// ...
}