3

I've implemented a very based ParallelFor algorithm as follows:

inline void ParallelFor( const size_t startIdx, const size_t endIdx, std::function< void( size_t ) >&& fn, const size_t numThreads = std::thread::hardware_concurrency() )
{
    const size_t portion = std::max( 1, (endIdx - startIdx) / numThreads );
    std::vector< std::thread > threads;
    for ( size_t i = startIdx; i < endIdx; i += portion )
    {
        int from    = i;
        int to      = (i + portion) <= endIdx ? (i + portion) : endIdx;

        threads.push_back( std::thread( [=,&fn]() 
            {
                for ( int j = from; j < to; ++j )
                    fn( j );
            } ) );
    }
    std::for_each( threads.begin(), threads.end(), []( std::thread& x ) 
        { 
            x.join();
        } );
}

However when I build it says that the threads.push_back function is "attempting to reference a deleted function".

I can't understand what I'm doing wrong. Can someone point out where I'm going wrong?

EDIT: The compiler is VStudio 2015

There is tonnes more to the error as follows:

1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(657): error C2280: 'std::thread::thread(const std::thread &)': attempting to reference a deleted function
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thread(73): note: see declaration of 'std::thread::thread'
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(775): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,const std::thread&>(_Objty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Ty=std::thread,
1>              _Objty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(775): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,const std::thread&>(_Objty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Ty=std::thread,
1>              _Objty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(920): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const std::thread&>(std::allocator<_Ty> &,_Objty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<std::thread>,
1>              _Ty=std::thread,
1>              _Objty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0(920): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,const std::thread&>(std::allocator<_Ty> &,_Objty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<std::thread>,
1>              _Ty=std::thread,
1>              _Objty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory(379): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<std::thread,const std::thread&>(_Ty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Ty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory(379): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<std::thread,const std::thread&>(_Ty *,const std::thread &)' being compiled
1>          with
1>          [
1>              _Ty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory(416): note: see reference to function template instantiation '_FwdIt std::_Uninit_copy<_InIt,_FwdIt,std::allocator<_Ty>>(_InIt,_InIt,_FwdIt,std::_Wrap_alloc<std::allocator<_Ty>> &,std::_Nonscalar_ptr_iterator_tag)' being compiled
1>          with
1>          [
1>              _FwdIt=std::thread *,
1>              _InIt=const std::thread *,
1>              _Ty=std::thread
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory(427): note: see reference to function template instantiation '_FwdIt std::_Uninit_copy<const std::thread*,_Iter,_Alloc>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled
1>          with
1>          [
1>              _FwdIt=std::thread *,
1>              _Iter=std::thread *,
1>              _Alloc=std::_Wrap_alloc<std::allocator<std::thread>>,
1>              _InIt=const std::thread *
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(1672): note: see reference to function template instantiation '_FwdIt std::_Uninitialized_copy<_Iter,std::thread*,std::_Wrap_alloc<std::allocator<_Ty>>>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled
1>          with
1>          [
1>              _FwdIt=std::thread *,
1>              _Iter=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>,
1>              _Ty=std::thread,
1>              _InIt=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>,
1>              _Alloc=std::_Wrap_alloc<std::allocator<std::thread>>
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(751): note: see reference to function template instantiation 'std::thread *std::vector<std::thread,std::allocator<_Ty>>::_Ucopy<std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>>(_Iter,_Iter,std::thread *)' being compiled
1>          with
1>          [
1>              _Ty=std::thread,
1>              _Iter=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(751): note: see reference to function template instantiation 'std::thread *std::vector<std::thread,std::allocator<_Ty>>::_Ucopy<std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>>(_Iter,_Iter,std::thread *)' being compiled
1>          with
1>          [
1>              _Ty=std::thread,
1>              _Iter=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::thread>>>
1>          ]
1>  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(742): note: while compiling class template member function 'std::vector<std::thread,std::allocator<_Ty>>::vector(const std::vector<_Ty,std::allocator<_Ty>> &)'
1>          with
1>          [
1>              _Ty=std::thread
1>          ]
14
  • What compiler is this, and is there any more to the error? Commented Oct 2, 2015 at 11:01
  • Possible duplicate of Error C2280: 'std::thread::thread(const std::thread &)' : attempting to reference a deleted function Commented Oct 2, 2015 at 11:03
  • @Mgetz: If there IS an answer at that then can someone please explain it to me because it doesn't seem relevant to my problem (I have already checked it though) Commented Oct 2, 2015 at 11:07
  • 1
    @Goz it's exactly your issue, you're attempting to COPY a std::thread which is move only Commented Oct 2, 2015 at 11:08
  • @Mgetz: Except he's not. He's constructing a temporary, which should be going to the rvalue version of push_back. See ideone.com/r5rdKF (which uses a different compiler). Commented Oct 2, 2015 at 11:08

1 Answer 1

3

I can't immediately see an issue, as it works as is on gcc. I suspect that the compiler isn't calling the proper push_back overload.

I would try using emplace back instead.

  threads.emplace_back(  [=,&fn]() 
             {
                for ( int j = from; j < to; ++j )
                    fn( j );
             }  );

Edit: Since apparently the compiler doesn't support the emplace back either, I would probably fall back to std::vector<std::shared_ptr<std::thread> >, and change the insertion code to

  threads.emplace_back( std::make_shared<std::thread>( [=,&fn]() 
             {
                for ( int j = from; j < to; ++j )
                    fn( j );
             }  ) );

There has to be a change on the join loop as well.

Sign up to request clarification or add additional context in comments.

2 Comments

@DaveS: Yeah thats one way of dealing with it ... how annoying. Thanks for the help!
So I just tested the very basic case that @Goz is doing above, simple lambda into a thread constructor and then push_back the temporary. That works

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.