Boost logo

Boost Users :

Subject: Re: [Boost-users] [boost][thread] Future returning 0xfeeefeee
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2013-04-07 17:19:50


Le 07/04/13 22:48, Vicente J. Botet Escriba a écrit :
> Le 07/04/13 21:24, Klaim - Joël Lamotte a écrit :
>>
>> On Sun, Apr 7, 2013 at 8:05 PM, Vicente J. Botet Escriba
>> <vicente.botet_at_[hidden] <mailto:vicente.botet_at_[hidden]>> wrote:
>>
>> Maybe, there is a difference between the interface std::vector
>> you use in this example and your WorkQueue. Could you provide the
>> prototype of the functions you are using of WorkQueue?
>>
>>
>> Yes that's what I reported before: this code works until you use both
>> boost::future/promise AND WorkQueue. I currently fixed production my
>> code by just using std::future/promise.
>> I've provided the full source code of WorkQueue in my first mail.
>> I'll re-provide it here.
>> It's a thin wrapper around a
>> tbb::concurrent_queue<std::function<void()>> . (I'm using TBB 4.1 U2)
>> Unfortunately the only clue that I can think about is that this
>> container don't allow move-only value-type, so maybe it's linked to
>> the problem
>> but if not I have no idea.
>> I also reported in the tbb forum see if they can spot something but
>> the mix makes things hard to understand.
>>
>> Joel Lamotte
>>
>> ----
>>
>> class WorkQueue
>> {
>> public:
>>
>> template< class WorkTask >
>> void push( WorkTask&& task )
>> {
>> m_task_queue.push( std::forward<WorkTask>( task ) );
>> }
>>
>> /** Execute all the work queued until now. */
>> void execute()
>> {
>> if( m_task_queue.empty() )
>> return;
>>
>> bool end_of_work = false;
>> m_task_queue.push( [&]{ end_of_work = true; } );
>>
>> std::function<void()> work;
>> while( !end_of_work && m_task_queue.try_pop( work ) )
>> {
>> work();
>> }
>> }
>>
>> private:
>>
>> mutable tbb::concurrent_queue< std::function<void()> > m_task_queue;
>> };
>>
>>
> The main difference I see is the way the function is obtained:
>
>
> When using vector the 'work' variable is a reference to the queue
> back, there is no move no assignment of function<void()> objects.
>
> auto work = work_queue.back();
> work_queue.pop_back();
>
> When using tbb the 'work' variable is default constructed and copied
> using try_pop (see below).
>
> std::function<void()> work;
> while( !end_of_work && m_task_queue.try_pop( work ) )
>
> I suspect that there could be an issue with the Boost.Thread
> implementation here.
>
> I don't master lambdas yet: does this the following code mean that
> work_queue is taken by reference and promise by value on the pushed
> lambda object?
>
> auto do_some_work = [&]()-> boost::future<int*>
> {
> auto promise = std::make_shared<boost::promise<int*>>();
> work_queue.push_back( [=]
> {
> promise->set_value( &TRUC );
> });
>
> return promise->get_future();
>
> };
>
>
> ----------------------
> From tbb documentation
>
> bool try_pop ( T& destination )
>
> If value is available, pops it from the queue, assigns it to
> destination, and destroys the original value. Otherwise does nothing.
>
> *Returns*: True if value was popped; false otherwise.
>
>
I've changed the example to force copy semantics with std::vector

#define BOOST_THREAD_VERSION 4

#include <cassert>
#include <vector>
#include <future>
#include <functional>
#include <boost/thread/future.hpp>

int TRUC = 42;
int main()
{
    std::vector< std::function<void()> > work_queue;

   auto do_some_work = [&]()-> boost::future<int*>
   {
     auto promise = std::make_shared<boost::promise<int*>>();
#if 0
     work_queue.push_back( [=]
     {
       promise->set_value( &TRUC );
     });
#else
     auto inner = [=]()
     {
       promise->set_value( &TRUC );
     };
     work_queue.push_back(inner);

#endif

     return promise->get_future();

   };

   auto ft_value = do_some_work();

   while( !work_queue.empty() )
    {
#if 0
       auto work = work_queue.back();
#else
       std::function<void()> work;
       work = work_queue.back();
#endif
       work_queue.pop_back();
       work();
    }

   auto value = ft_value.get();
   assert( value == &TRUC );
   return 0;
}

Could you try it on your environment?

Best,
Vicente



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net