2017-01-28 5 views
1

Я работаю с потоками в первый раз на C++, и я хотел бы знать, что не так с моим кодом.C++ Создание потоков в цикле и сохранение их в векторе

Я работаю над алгоритмом Boruvka, и я хотел бы создать темы для поиска кратчайшего Edge для компонента.

Вот мой код:

std::vector<std::thread> threads; 
    std::vector<Edge> minEdges; 

    for (auto g: components) { 
     Edge minEd; 
     minEdges.push_back(minEd); 
     threads.push_back(std::thread (findPath, g, std::ref(minEdges.back()))); 
    } 
    for (auto &i : threads) { 
     i.join(); 
    } 
    for (Edge edge:minEdges) { 
     if (!contains(mst, edge)) { 
      addEdge(&mst, edge.n1, edge.n2, edge.weight); 
     } 
    } 

void findPath(Graph &component, Edge &edge) 
//finds cheapest edge 

Для exlanation, я хотел бы дать компонент и ссылку на элемент в minEdges, где будут храниться самые края. Затем я хочу присоединиться ко всем потокам и поместить все минимальные ребра в mst.

Этот код дает мне ошибку в строке, где I`m толкает потоки к вектору, но я не мог найти почему. Так что, пожалуйста, скажите мне?

Сообщение об ошибке (я просто удалил пути к файлам):

In instantiation of 'struct std::_Bind_simple<void (*(Graph, std::reference_wrapper<Edge>))(Graph&, Edge&)>': 
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/thread:142:59: 
required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(Graph&, Edge&); _Args = {Graph&, std::reference_wrapper<Edge>}]' 
graph.cpp:232:82: required from here 
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(Graph, std::reference_wrapper<Edge>))(Graph&, Edge&)>' 
    typedef typename result_of<_Callable(_Args...)>::type result_type; 
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(Graph, std::reference_wrapper<Edge>))(Graph&, Edge&)>' 
    _M_invoke(_Index_tuple<_Indices...>) 
    ^
                 ^

Спасибо за ответы.

+0

Извините, я его отредактировал. –

+1

Что происходит, когда вы используете std :: ref на g? – Niall

+1

Off topic: передача ссылок на векторные элементы в поток при нажатии элементов в векторе приводит к высокому риску того, что ссылки будут отображаться недействительными с помощью изменения размера, прежде чем потоки получат возможность запуска. – user4581301

ответ

0

Несколько пунктов ...

  1. Не изменять векторы, которые уже используются другими нитями (добавление к вектору может переместить другие элементы)

  2. перебирать ссылки, не временные конструкции (auto g)

  3. Предпочитают emplace_back всякий раз, когда возможный

  4. По желанию попробовать с синтаксисом лямбда-

  5. Используйте синхронизацию, чтобы убедиться, все происходит в порядке, вы думаете, что они (не требуется в вашем случае - создание нити действует как забор памяти)

std::vector<Edge> minEdges; 
    for (auto &g: components) { 
     minEdges.emplace_back(); 
    } 

    std::vector<std::thread> threads; 
    for (size_t i=0; i<components.size(); ++i) { 
     threads.emplace_back([&]{findPath(components[i], minEdges[i]);}); 
    } 
    // rest of code... 
+0

Вам не хватает основной проблемы/точки, что при наличии нескольких потоков в игре доступ к общим структурам данных * должен быть * синхронизирован/сериализован. Ни в коем случае не обходимо - вам нужно использовать атомику или блокировку, если вы обновляете вещи в разных потоках - никакое количество ссылок на ссылки или emplace_back не спасет вас. Годом данных является гонка данных. –

+0

@JesperJuhl - чтение одной и той же памяти не нужно синхронизировать, если оно никогда не изменяется. Здесь нет гонки данных. – rustyx

+0

'minEdges' изменен в основном потоке и доступен (прочитан) в других потоках без синхронизации - там есть гонка. –

Смежные вопросы