Подтвердить что ты не робот

С++: error: no type с именем 'type in' class 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;
...

Взял время, но все равно не может его исправить. Спасибо.

4b9b3361

Ответ 1

Я смог скомпилировать ваш код с помощью MSVC2013. Однако thread() выполняет передачу своих аргументов в новый поток. Это означает, что если ваш код будет компилироваться на вашем компиляторе, каждый поток будет запускаться со своей собственной копией ht, так что в конце main ht будет пустым.

GCC не компилируется с этим странным сообщением. Вы можете избавиться от него, используя ссылочный wraper с потоком:

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

Ответ 2

Ошибка очень загадочна, но проблема в том, что 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);

    // ...
}

[Живой пример]