2015-06-10 4 views
7

Я создаю программное обеспечение реального времени, где у меня есть основные бесконечные петли на main() и потоки, используемые для чтения и обработки данных.C++ std :: vector of independent std :: threads

Одной из проблем является сохранение std::vector выполняемых потоков для отправки сигналов на них и контроля выполнения. Так я соединял этот код:

#include <iostream> 
#include <string> 
#include <vector> 
#include <thread> 
#include <chrono> 

namespace readerThread { 

    void start(int id) 
    { 
     while (1) 
     { 
      std::cout << "Reader " << id << " running..." << std::endl; 
      std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 
     } 
    } 

} 


int main() 
{ 

     int readers[] = { 1, 2, 3 }; 

     std::vector<std::thread> readerThreads; 

     for (int &reader : readers) 
     { 
      std::thread th(readerThread::start, reader); 
      readerThreads.push_back(th); 
     } 

     while(true) 
     { 
      std::cout << "Waiting..." << std::endl; 
      std::this_thread::sleep_for(std::chrono::milliseconds(10000)); 
     } 

     return 0; 
} 

Он даже компилировать это не распространяется, получаю эту ошибку:

In file included from /usr/local/include/c++/5.1.0/x86_64-unknown-linux-gnu/bits/c++allocator.h:33:0, 
       from /usr/local/include/c++/5.1.0/bits/allocator.h:46, 
       from /usr/local/include/c++/5.1.0/string:41, 
       from /usr/local/include/c++/5.1.0/bits/locale_classes.h:40, 
       from /usr/local/include/c++/5.1.0/bits/ios_base.h:41, 
       from /usr/local/include/c++/5.1.0/ios:42, 
       from /usr/local/include/c++/5.1.0/ostream:38, 
       from /usr/local/include/c++/5.1.0/iostream:39, 
       from main.cpp:1: 
/usr/local/include/c++/5.1.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {const std::thread&}; _Tp = std::thread]': 
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:256:4: required from 'static std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > = void]' 
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:402:16: required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]' 
/usr/local/include/c++/5.1.0/bits/stl_vector.h:917:30: required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::value_type = std::thread]' 
main.cpp:37:30: required from here 
/usr/local/include/c++/5.1.0/ext/new_allocator.h:120:4: error: use of deleted function 'std::thread::thread(const std::thread&)' 
    { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } 
    ^
In file included from main.cpp:4:0: 
/usr/local/include/c++/5.1.0/thread:126:5: note: declared here 
    thread(const thread&) = delete; 
    ^

Нити areindependent, поэтому Я не нужно позвонить join по основной программе, ни на любом потоке ...

Итак, вот мои сомнения:

Почему мой код не компилируется?

Это правильный способ хранения вектора потоков?

Спасибо за помощь ...

PS: Original code here:

+0

Если вы планируете прекратить свое приложение правильно, вы должны вызвать 'join()' до того, как объект thread будет уничтожен. Или вызовите 'detach()' для отсоединения потока от объекта. В противном случае вы получите 'terminate()' call in thread destructor. – gomons

+0

Гомоны, не получили вашу мысль. join() будет удерживать выполнение основного потока, и это не нужно здесь ... – Mendes

+0

Вы также можете использовать 'readerThreads.emplace_back (readerThread :: start, reader);', Что означает gomons, означает, что вы должны либо «присоединиться»() 'или' detach() 'экземпляр потока до выполнения его деструктора, иначе вызывается' terminate() '. Но ваши потоки кажутся вполне счастливыми работать вечно, так что это не проблема в приведенном выше примере. – Praetorian

ответ

11

Вы должны использовать что-то вроде

readerThreads.push_back(move(th)); 

Это сделает th в RValue, и вызывают перемещение CTOR называться , Копия ctor thread была disabled по дизайну (см. Энтони Уильямс C++ Concurrency In Action).

+2

Да! Теперь я помню это из других чтений .. Спасибо за помощь ... Работаю как шарм ... – Mendes

6
/usr/local/include/c++/5.1.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {const std::thread&}; _Tp = std::thread]': 
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:256:4: required from 'static std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > = void]' 
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:402:16: required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]' 
/usr/local/include/c++/5.1.0/bits/stl_vector.h:917:30: required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::value_type = std::thread]' 
main.cpp:37:30: required from here 
/usr/local/include/c++/5.1.0/ext/new_allocator.h:120:4: error: use of deleted function 'std::thread::thread(const std::thread&)' 
    { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } 

Позволяет отслаивать эту спину немного.

error: use of deleted function 'std::thread::thread(const std::thread&)' 

Ваш код делает что-то, что попытки ввести std::thread.

required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) 

push_back является виновником.

std::thread не подлежит редактированию - что бы это было означает чтобы скопировать тему?

std::thread t1([](){}); 
std::thread t2 = t1; 

Так экземпляры std::thread объектов предназначены для уникальных владельцев. Помимо простой путаницы, возникла бы боль.

Они, однако, подвижны.

std::thread t1([](){}); 
std::thread t2 = std::move(t1); 

t1 не-больше допустимый описатель нити, нить он описывал в настоящее время принадлежит t2.

Для размещения таких вещей в контейнере вы можете использовать std::move или std::emplace/std::emplace_back.

std::vector<std::thread> threads; 
threads.push_back(std::move(std::thread([](){}))); 
threads.emplace_back([](){}); 

В то время как ваш код сосредоточив внимание на данном вопросе, позвольте мне отметить, что стандарт C++ объявляет это как ошибку на поток деструктор будет вызван в то время как поток все еще прикреплен и не присоединился.

int main() { 
    std::thread t1([](){ while (true) { std::this_thread::yield(); } }; 
} 

Когда основные заканчивается, t1. ~ Нить() вызывается, который обнаруживает, что поток все еще прикреплен и не присоединились, это вызывает исключение вызывает сбой выключения.

Вам необходимо либо join() нить, ожидая ее окончания работы, либо detach(). Вам нужно каким-то образом остановить поток, если вы хотите использовать join(), и если вы выполните detach(), программа может выйти в середине потока, выполняя что-то вроде записи данных и т. Д., Вы можете ввести серьезную ошибку.

#include <thread> 
#include <chrono> 
#include <future> 

int main() { 
    std::promise<void> cnx_promise; 
    std::shared_future<void> cnx_future; 

    std::thread t1([cnx_future]() { 
     while (cnx_future.valid()) { 
     std::this_thread::yield(); 
     } 
    }); 

    std::this_thread::sleep_for(std::chrono::seconds(1)); 

    cnx_promise.set_value(); 

    t1.join(); 
} 

Здесь мы используем обещание, чтобы нить знает, когда пришло время, чтобы остановить бег, но вы можете использовать переменные условия, сигналы и т.д., или даже только простой std::atomic<bool> ok_to_run { true };, что вы проверить на ложь.

1

Другим вариантом, который работает, является создание объекта потока в вызове vector.push_back. Нет необходимости вызывать std :: move в этом случае, потому что его уже rvalue (таким образом, он будет перемещен).

for (int &reader : readers) 
    readerThreads.push_back(std::thread(readerThread::start, reader)); 
+0

Простейший и лучший ответ. – JulianSoto

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

  • Нет связанных вопросов^_^