init-capture richtig anwenden
-
Hallo an alle,
ich wollte diesen ThreadPool benutzen.
Der Autor benutzt jedoch in seiner enqueue-Funktion einen hässlichen shared_ptr-Hack (da in C++11 init-capture nicht unterstützt wurde).In meinem Programm wollte ich nun die enqueue-Funktion "umschreiben", sodass ich mir die Konstruktion eines shared_ptrs sparen kann. Leider funktioniert dies auf VS 2015 nicht so richtig (Siehe Code und Fehlermeldungen unten) - anscheinend wende ich init-capture falsch an. Ich wäre euch sehr verbunden, wenn ihr mir erklären könntet, wie ich das syntaktisch zu schreiben hab .
Danke und mfG
shft
Code
#include <vector> #include <queue> #include <memory> #include <thread> #include <mutex> #include <condition_variable> #include <future> #include <functional> #include <stdexcept> using namespace std; // Die Klasse ThreadPool aus GitHub (ThreadPool.h) class ThreadPool { public: ThreadPool( size_t ); template<class F , class... Args> auto enqueue( F&& f , Args&&... args ) ->std::future<typename std::result_of<F( Args... )>::type>; ~ThreadPool(); private: // need to keep track of threads so we can join them std::vector< std::thread > workers; // the task queue std::queue< std::function<void()> > tasks; // synchronization std::mutex queue_mutex; std::condition_variable condition; bool stop; }; // the constructor just launches some amount of workers inline ThreadPool::ThreadPool( size_t threads ) : stop( false ) { for( size_t i = 0; i<threads; ++i ) workers.emplace_back( [this] { for( ;;) { std::function<void()> task; { std::unique_lock<std::mutex> lock( this->queue_mutex ); this->condition.wait( lock , [this] { return this->stop || !this->tasks.empty(); } ); if( this->stop && this->tasks.empty() ) return; task = std::move( this->tasks.front() ); this->tasks.pop(); } task(); } } ); } // In dieser Funktion wird es interessant // add new work item to the pool template<class F , class... Args> auto ThreadPool::enqueue( F&& f , Args&&... args ) -> std::future<typename std::result_of<F( Args... )>::type> { using return_type = typename std::result_of<F( Args... )>::type; // make_shared entfernt. task ist nun direkt ein packeged_task auto task = std::packaged_task<return_type()>( std::bind( std::forward<F>( f ) , std::forward<Args>( args )... ) ); // Statt -> nun ein . std::future<return_type> res = task.get_future(); { std::unique_lock<std::mutex> lock( queue_mutex ); // don't allow enqueueing after stopping the pool if( stop ) throw std::runtime_error( "enqueue on stopped ThreadPool" ); // init-capture mit Move-Semantik tasks.emplace( [t{ move( task ) }]() mutable { t(); } ); } condition.notify_one(); return res; } // the destructor joins all threads inline ThreadPool::~ThreadPool() { { std::unique_lock<std::mutex> lock( queue_mutex ); stop = true; } condition.notify_all(); for( std::thread &worker : workers ) worker.join(); } void x() { cout << "Hallo Welt!\n"; } int main() { ThreadPool p{ 1 }; p.enqueue( &x ); cin.get(); return 0; }
Fehler
1>microsoft visual studio 14.0\vc\include\xutility(288): error C2280: "ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>(const ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &)" : Es wurde versucht, auf eine gelöschte Funktion zu verweisen 1> main.cpp(97): note: Siehe Deklaration von "ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>" 1> microsoft visual studio 14.0\vc\include\functional(164): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Compressed_pair<_Alloc,_Callable,true>::_Compressed_pair<const _Alloc&,const _Callable&>(std::_One_then_variadic_args_t,_Other1,const _Callable &)". 1> with 1> [ 1> _Alloc=std::allocator<int>, 1> _Callable=_Decayed, 1> _Other1=const std::allocator<int> & 1> ] 1> microsoft visual studio 14.0\vc\include\functional(162): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Compressed_pair<_Alloc,_Callable,true>::_Compressed_pair<const _Alloc&,const _Callable&>(std::_One_then_variadic_args_t,_Other1,const _Callable &)". 1> with 1> [ 1> _Alloc=std::allocator<int>, 1> _Callable=_Decayed, 1> _Other1=const std::allocator<int> & 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(737): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Func_impl<_Decayed,_Alloc,_Ret>::_Func_impl<const _Callable&,const _Alloc&>(_Other1,_Other2)". 1> with 1> [ 1> _Alloc=std::allocator<int>, 1> _Ret=void, 1> _Callable=_Decayed, 1> _Other1=const _Decayed &, 1> _Other2=const std::allocator<int> & 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(737): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Func_impl<_Decayed,_Alloc,_Ret>::_Func_impl<const _Callable&,const _Alloc&>(_Other1,_Other2)". 1> with 1> [ 1> _Alloc=std::allocator<int>, 1> _Ret=void, 1> _Callable=_Decayed, 1> _Other1=const _Decayed &, 1> _Other2=const std::allocator<int> & 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(857): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator<_Other>::construct<_Objty,const _Callable&,const _Alloc&>(_Objty *,const _Callable &,const _Alloc &)". 1> with 1> [ 1> _Other=_Myimpl, 1> _Objty=std::_Func_impl<_Decayed,std::allocator<int>,void>, 1> _Callable=_Decayed, 1> _Alloc=std::allocator<int> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(857): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator<_Other>::construct<_Objty,const _Callable&,const _Alloc&>(_Objty *,const _Callable &,const _Alloc &)". 1> with 1> [ 1> _Other=_Myimpl, 1> _Objty=std::_Func_impl<_Decayed,std::allocator<int>,void>, 1> _Callable=_Decayed, 1> _Alloc=std::allocator<int> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(996): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator_traits<_Alloc>::construct<_Ty,const _Callable&,const std::allocator<int>&>(std::allocator<_Ty> &,_Objty *,const _Callable &,const std::allocator<int> &)". 1> with 1> [ 1> _Alloc=std::allocator<_Myimpl>, 1> _Ty=std::_Func_impl<_Decayed,std::allocator<int>,void>, 1> _Callable=_Decayed, 1> _Objty=std::_Func_impl<_Decayed,std::allocator<int>,void> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(995): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator_traits<_Alloc>::construct<_Ty,const _Callable&,const std::allocator<int>&>(std::allocator<_Ty> &,_Objty *,const _Callable &,const std::allocator<int> &)". 1> with 1> [ 1> _Alloc=std::allocator<_Myimpl>, 1> _Ty=std::_Func_impl<_Decayed,std::allocator<int>,void>, 1> _Callable=_Decayed, 1> _Objty=std::_Func_impl<_Decayed,std::allocator<int>,void> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(198): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Wrap_alloc<std::allocator<_Other>>::construct<std::_Func_impl<_Decayed,_Alloc,_Ret>,const _Callable&,const _Alloc&>(_Ty *,const _Callable &,const _Alloc &)". 1> with 1> [ 1> _Other=_Myimpl, 1> _Alloc=std::allocator<int>, 1> _Ret=void, 1> _Callable=_Decayed, 1> _Ty=std::_Func_impl<_Decayed,std::allocator<int>,void> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(198): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Wrap_alloc<std::allocator<_Other>>::construct<std::_Func_impl<_Decayed,_Alloc,_Ret>,const _Callable&,const _Alloc&>(_Ty *,const _Callable &,const _Alloc &)". 1> with 1> [ 1> _Other=_Myimpl, 1> _Alloc=std::allocator<int>, 1> _Ret=void, 1> _Callable=_Decayed, 1> _Ty=std::_Func_impl<_Decayed,std::allocator<int>,void> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(174): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Func_base<_Ret> *std::_Func_impl<_Decayed,_Alloc,_Ret>::_Clone<void>(_Void *,std::false_type) const". 1> with 1> [ 1> _Ret=void, 1> _Alloc=std::allocator<int>, 1> _Void=void 1> ] 1> microsoft visual studio 14.0\vc\include\functional(174): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::_Func_base<_Ret> *std::_Func_impl<_Decayed,_Alloc,_Ret>::_Clone<void>(_Void *,std::false_type) const". 1> with 1> [ 1> _Ret=void, 1> _Alloc=std::allocator<int>, 1> _Void=void 1> ] 1> microsoft visual studio 14.0\vc\include\functional(173): note: Bei der Kompilierung der Klassen-template der "std::_Func_base<_Ret> *std::_Func_impl<_Decayed,_Alloc,_Ret>::_Copy(void *) const"-Memberfunktion 1> with 1> [ 1> _Ret=void, 1> _Alloc=std::allocator<int> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(137): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "std::_Func_impl<_Decayed,_Alloc,_Ret>". 1> with 1> [ 1> _Alloc=std::allocator<int>, 1> _Ret=void 1> ] 1> microsoft visual studio 14.0\vc\include\functional(348): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "std::_Is_large<_Myimpl>". 1> microsoft visual studio 14.0\vc\include\functional(327): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)". 1> with 1> [ 1> _Ret=void, 1> _Ty=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Alloc=std::allocator<int> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(327): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)". 1> with 1> [ 1> _Ret=void, 1> _Ty=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Alloc=std::allocator<int> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(498): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Func_class<_Ret>::_Reset<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Fx &&)". 1> with 1> [ 1> _Ret=void, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> 1> ] 1> microsoft visual studio 14.0\vc\include\functional(498): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Func_class<_Ret>::_Reset<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Fx &&)". 1> with 1> [ 1> _Ret=void, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(737): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::function<void (void)>::function<_Ty,void,void>(_Fx)". 1> with 1> [ 1> _Ty=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(737): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::function<void (void)>::function<_Ty,void,void>(_Fx)". 1> with 1> [ 1> _Ty=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>, 1> _Fx=ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(857): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator<_Ty>::construct<_Objty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Objty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)>, 1> _Objty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(857): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator<_Ty>::construct<_Objty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Objty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)>, 1> _Objty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(996): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator_traits<_Alloc>::construct<_Ty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(std::allocator<_Ty> &,_Objty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Alloc=std::allocator<std::function<void (void)>>, 1> _Ty=std::function<void (void)>, 1> _Objty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\xmemory0(995): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::allocator_traits<_Alloc>::construct<_Ty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(std::allocator<_Ty> &,_Objty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Alloc=std::allocator<std::function<void (void)>>, 1> _Ty=std::function<void (void)>, 1> _Objty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\deque(1190): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Wrap_alloc<std::allocator<_Ty>>::construct<_Ty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Ty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\deque(1188): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Wrap_alloc<std::allocator<_Ty>>::construct<_Ty,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(_Ty *,ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\queue(116): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::deque<_Ty,std::allocator<_Ty>>::emplace_back<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> microsoft visual studio 14.0\vc\include\queue(116): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::deque<_Ty,std::allocator<_Ty>>::emplace_back<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> main.cpp(97): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::queue<std::function<void (void)>,std::deque<_Ty,std::allocator<_Ty>>>::emplace<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> main.cpp(97): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::queue<std::function<void (void)>,std::deque<_Ty,std::allocator<_Ty>>>::emplace<ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295>>(ThreadPool::enqueue::<lambda_9dcfeffa0f4dc76eeddda8723ddb7295> &&)". 1> with 1> [ 1> _Ty=std::function<void (void)> 1> ] 1> main.cpp(148): note: Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::future<void> ThreadPool::enqueue<void(__cdecl *)(void),>(F &&)". 1> with 1> [ 1> F=void (__cdecl *)(void) 1> ]
-
Wird der Lambdaausdruck nicht kopiert, wenn man ihn in eine std::function packen will? Das kann aber nicht funktionieren, wenn ein nicht kopierbarer packaged_task enthalten ist.
-
Hm, das könnte das Problem sein.
Ich habe mal versucht, ob es funktioniert, wenn ich aus std::queue<std::function<void()>> eine std::queue<std::unique_ptr<std::function<void()>>> mache, aber leider hatte ich auch damit kein ErfolgDann bleibt wohl nur, den shared_ptr-Hack beizubehalten