Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
7 Views

Concurrent_queue potential bug: Promise/Future returning 0xfeeefeee

I'm stuck with a problem I quite don't understand and that involve either boost::future/promise or tbb::concurrent_queue, or my understanding of using both. I think there is a high probability that someone here will point to the problem, but I will report too to the tbb forum Some context: - I'm using VS2012 Update 2 - it's 32 bit DEBUG mode - I use Boost.Thread V4 (in CMake I set "add_definitions( -DBOOST_THREAD_VERSION=4 )" to force it ) - I use TBB 4.1 Update 2 I've setup a test (using GTest) which reproduce the problem: ############ int TRUC = 42; TEST( Test_WorkQueue, future_promise_shared_work ) { WorkQueue work_queue; // I'm doing this like that because it reflect the use case I have, // I didn't find another way to have the promise alive in a container which don't allow move semantic auto do_some_work = [&]()-> boost::future { struct K { boost::promise promise; void foo() { promise.set_value( &TRUC ); } }; auto object_ptr = std::make_shared(); // D: work_queue.push( [=] { object_ptr->foo(); }); return object_ptr->promise.get_future(); }; auto ft_value = do_some_work(); work_queue.execute(); auto value = ft_value.get(); ASSERT_EQ( &TRUC, value ); // this fails, value == 0xfeeefeee } ########## My WorkQueue type use tbb::concurrent_queue and is defined as: ########## class WorkQueue { public: template< class WorkTask > void push( WorkTask&& task ) { m_task_queue.push( std::forward( 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 work; while( !end_of_work && m_task_queue.try_pop( work ) ) { work(); } } private: mutable tbb::concurrent_queue< std::function > m_task_queue; }; ############ It's basically a simple wrapper around the concurrent_queue, but maybe the execute() code have an impact. THE PROBLEM: The test fails. value == 0xfeeefeee as soon as the get() call is done. Using the debugger, I can't figure where the data is lost. It seem that everything is correct until when all the hierarchy of function call returns the result...which is different and wrong once out of the function. I first wrote this test with std::vector< std::function > instead of the concurrent queue to check if it was boost::future/promise which was not working well with Boost.Thread V4. With the vector instead of concurrent_queue, the code works perfectly. Does someone have an idea what is going on? Joel Lamotte
0 Kudos
2 Replies
Highlighted
Beginner
7 Views

I just replaced boost::future/promise by std::future/promise and the test just works. However the same change in a real code using WorkQueue internally and using similar code to the test makes the future::get() provide invalid pointers with values close to 0x000000 but not exactly. This code then makes access violation as the pointers are obviously not valid. So far I know: - having a std::vector instead of tbb::concurrent_queue makes the test work (the real code can't use std::vector, it's concurrent); - using std::future/promise instead of boost::future/promise makes the test work ...; - ...but not the real code (which should be almost the same than the test); My current suspicion: maybe I do something wrong with the lifetime of the promise? I don't see what unfortunately. I'll try to reproduce the problem with std::future/promise I see in my real code but in the test. Joel Lamotte
0 Kudos
Highlighted
Beginner
7 Views

Ok I found that my "real code" is actually buggy and indeed provide a wrong pointer (for a reason I'll have to hunt). So don't bother, std::future/promise does work with my test and real code using WorkQueue/tbb::concurrent_queue but boost::future/promise doesnt. I also simplified the test (and real) code for clarity, it should be equivalent to the code from my first post: int TRUC = 42; TEST( Test_WorkQueue, future_promise_shared_work ) { WorkQueue work_queue; auto do_some_work = [&]()-> std::future { auto promise = std::make_shared<:PROMISE>>(); work_queue.push( [=] { promise->set_value( &TRUC ); }); return promise->get_future(); }; auto ft_value = do_some_work(); work_queue.execute(); auto value = ft_value.get(); ASSERT_EQ( &TRUC, value ); }
0 Kudos