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 Erfolg 😞

    Dann bleibt wohl nur, den shared_ptr-Hack beizubehalten 😣


Anmelden zum Antworten