Re: [Boost-users] [boost][thread] Future returning 0xfeeefeee
Zitat von Klaim - Joël Lamotte <mjklaim@gmail.com>:
On Sun, Apr 7, 2013 at 1:02 AM, Klaim - Joël Lamotte <mjklaim@gmail.com>wrote:
So the promise is destroyed before setting the value to the future.
Sorry, I meant: the promise is (a priori) guaranteed to be destroyed AFTER having set the value to the future.
Joel Lamotte
I was under the impression that the promise object itself has to be alive when the future result is used. and since you're emptying your queue on execution it's not. but considering that the promise object could be in another thread that was probably a false impression. Which compiler does this even work with yet? Both gcc and clang fail. clang on compilation, gcc compiles it but fails at runtime with a system_error exception and an invalid error code. so you might wanna consider compiler and library bugs, too.
On Sun, Apr 7, 2013 at 1:44 AM, Stefan Strasser <strasser@uni-bremen.de>wrote:
I was under the impression that the promise object itself has to be alive when the future result is used. and since you're emptying your queue on execution it's not. but considering that the promise object could be in another thread that was probably a false impression.
I have doubts on this too. I think it is more useful for the promise and future to share the memory where the result will be set but not have a coupled lifetime. But I can't confirm yet, I'll have to search in the standard or find a language lawyer or someone knowing the SL well. Anyway, VC's std::promise/future seem to work as I intend in my test...
Which compiler does this even work with yet? Both gcc and clang fail. clang on compilation, gcc compiles it but fails at runtime with a system_error exception and an invalid error code. so you might wanna consider compiler and library bugs, too.
I tested only on Visual Studio 2012 Update 2. I don't see the problem with gcc/clang, could you provide error reports? I don't have access to them. However, here is a reproduction of the test but with a vector and std::future/promise: http://liveworkspace.org/code/2QT6d8$4 GCC 4.8 accepts it but not clang 3.2 apparently, but I believe it's a library implementation problem as the report point to std::chrono code that I don't even use directly. I cant' use Boost.Thread V4 on LiveWorkspace so my tests on these compilers are limited. Maybe just try http://liveworkspace.org/code/2QT6d8$4 but replace std::future and std::promise by boost::promise and see if it compiles. If it does, just add the WorkQueue code and replace the while loop by the call to execute, then you will have the exact code I'm testing. The queue works itself have some tests that run correctly, so the only problem I have is with boost::future/promise in combination with the tbb::concurrent_queue. As tbb::concurrent_queue don't allow move-only value type, I think that's the main difference with the vector, in the use case of my test. I really need some sleep now. Will get back to it tomorrow. Joel Lamotte
Le 07/04/13 02:12, Klaim - Joël Lamotte a écrit :
On Sun, Apr 7, 2013 at 1:44 AM, Stefan Strasser <strasser@uni-bremen.de <mailto:strasser@uni-bremen.de>> wrote:
I was under the impression that the promise object itself has to be alive when the future result is used. and since you're emptying your queue on execution it's not. but considering that the promise object could be in another thread that was probably a false impression.
I have doubts on this too. I think it is more useful for the promise and future to share the memory where the result will be set but not have a coupled lifetime. But I can't confirm yet, I'll have to search in the standard or find a language lawyer or someone knowing the SL well.
Anyway, VC's std::promise/future seem to work as I intend in my test...
Which compiler does this even work with yet? Both gcc and clang fail. clang on compilation, gcc compiles it but fails at runtime with a system_error exception and an invalid error code. so you might wanna consider compiler and library bugs, too.
I tested only on Visual Studio 2012 Update 2. I don't see the problem with gcc/clang, could you provide error reports? I don't have access to them.
However, here is a reproduction of the test but with a vector and std::future/promise: http://liveworkspace.org/code/2QT6d8$4 GCC 4.8 accepts it but not clang 3.2 apparently, but I believe it's a library implementation problem as the report point to std::chrono code that I don't even use directly.
I cant' use Boost.Thread V4 on LiveWorkspace so my tests on these compilers are limited. Maybe just try http://liveworkspace.org/code/2QT6d8$4 but replace std::future and std::promise by boost::promise and see if it compiles. If it does, just add the WorkQueue code and replace the while loop by the call to execute, then you will have the exact code I'm testing.
The queue works itself have some tests that run correctly, so the only problem I have is with boost::future/promise in combination with the tbb::concurrent_queue. As tbb::concurrent_queue don't allow move-only value type, I think that's the main difference with the vector, in the use case of my test.
I really need some sleep now. Will get back to it tomorrow.
Hi, I have tested your example on gcc-4.8.0 and clang-3.2 with libc++ and everything is ok. When I replace std::future/promise by boost::future/promise everything is ok also. 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? Best, Vicente
On Sun, Apr 7, 2013 at 8:05 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> 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; };
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@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> 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.
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@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> 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
On Sun, Apr 7, 2013 at 11:19 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
I've changed the example to force copy semantics with std::vector ... Could you try it on your environment?
Yes, I just tried it and I think I've mixed up things in previous email: - first, the two defines, as I was saying, seem exactly equivalent, but I still tried both, in doubt; - both cases, (#if 0 and #if 1) FAILS: 'value' is equal to DDDDDDDD in Debug mode in both cases. - I also tried with std::future/promise : both SUCCEED. So apparently the problem seem to lie only in boost::future/promise, not specifically with WorkQueue. I tested only inside my specific test environnement, to be certain I'll try again with an empty project. It's all under VS2012 , I'll try VS2010 too. Looks like another VC-specific problem for boost? Joel Lamotte
Le 07/04/13 23:38, Klaim - Joël Lamotte a écrit :
On Sun, Apr 7, 2013 at 11:19 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
I've changed the example to force copy semantics with std::vector ... Could you try it on your environment?
Yes, I just tried it and I think I've mixed up things in previous email: - first, the two defines, as I was saying, seem exactly equivalent, but I still tried both, in doubt;
Maybe you are right. I need to check the standard.
- both cases, (#if 0 and #if 1) FAILS: 'value' is equal to DDDDDDDD in Debug mode in both cases. - I also tried with std::future/promise : both SUCCEED.
So apparently the problem seem to lie only in boost::future/promise, not specifically with WorkQueue. Again you are surely right. I tested only inside my specific test environnement, to be certain I'll try again with an empty project.
It's all under VS2012 , I'll try VS2010 too. Looks like another VC-specific problem for boost?
I will be able to test with VS2010 tomorrow also, but not with VS2012. Vicente
On Mon, Apr 8, 2013 at 12:01 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
I will be able to test with VS2010 tomorrow also, but not with VS2012.
Do you confirm this code works correctly in your current env (gcc/clang)? Just to be sure, because of the liveworkspace fail. Joel Lamotte
Le 08/04/13 00:04, Klaim - Joël Lamotte a écrit :
On Mon, Apr 8, 2013 at 12:01 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
I will be able to test with VS2010 tomorrow also, but not with VS2012.
Do you confirm this code works correctly in your current env (gcc/clang)? Just to be sure, because of the liveworkspace fail.
Yes. I'm able to run them successfully on MAC-OS. clang could fails on liveworkspace because by default it doesn't uses libc++. Vicente
On Mon, Apr 8, 2013 at 12:13 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Yes. I'm able to run them successfully on MAC-OS.
Also, the MacOS doesn't provide the same stable version than the official clang release. Anyway, if you can test with gcc, it would be helpful too. Joel Lamotte
Klaim - Joël Lamotte wrote
On Mon, Apr 8, 2013 at 12:13 AM, Vicente J. Botet Escriba <
vicente.botet@
wrote:
Yes. I'm able to run them successfully on MAC-OS.
Also, the MacOS doesn't provide the same stable version than the official clang release. Anyway, if you can test with gcc, it would be helpful too.
As I said. I tested it with gcc-4.8.0 and clang-3.2. Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/boost-thread-Future-returning-0xfeeefeee-... Sent from the Boost - Users mailing list archive at Nabble.com.
Hi, On Mon, Apr 8, 2013 at 12:01 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
I will be able to test with VS2010 tomorrow also, but not with VS2012.
Did you have the time to check if the problem exists in your VS2010 setup?
Le 12/04/13 00:17, Klaim - Joël Lamotte a écrit :
Hi,
On Mon, Apr 8, 2013 at 12:01 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
I will be able to test with VS2010 tomorrow also, but not with VS2012.
Did you have the time to check if the problem exists in your VS2010 setup?
Unfortunately, no. I should have time to check it this weekend. Vicente
Le 12/04/13 08:18, Vicente J. Botet Escriba a écrit :
Le 12/04/13 00:17, Klaim - Joël Lamotte a écrit :
Hi,
On Mon, Apr 8, 2013 at 12:01 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
I will be able to test with VS2010 tomorrow also, but not with VS2012.
Did you have the time to check if the problem exists in your VS2010 setup?
Unfortunately, no. I should have time to check it this weekend.
Hi, I have had the time to check it on mingw. It works with gcc-4.8.0 and msvc-10.0. Best, Vicente
On Sun, Apr 14, 2013 at 3:11 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
I have had the time to check it on mingw. It works with gcc-4.8.0 and msvc-10.0.
Do you mean with trunk version of boost? Joel Lamotte
Le 14/04/13 16:17, Klaim - Joël Lamotte a écrit :
On Sun, Apr 14, 2013 at 3:11 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr <mailto:vicente.botet@wanadoo.fr>> wrote:
I have had the time to check it on mingw. It works with gcc-4.8.0 and msvc-10.0.
Do you mean with trunk version of boost?
Yes. Vicente
On Sun, Apr 7, 2013 at 11:19 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Could you try it on your environment?
I can now confirm, with empty console projects, with both VC10 and VC11 (last update for both): - your exact code gives 'value' == 0xfeeefeee - VC10 don't have <future> but VC11 does: using std::promise/future makes 'values' == &TRUC; - this is true whatever configuration of your defines I set (with 1 or 0); Notice that I just tried on liveworkspace, see if the code you gave would work on other compilers, it don't work with gcc4.8: http://liveworkspace.org/code/4j9pGu$1 We can't check with clang 3.2 unfortunately. We don't know if liveworkspace uses a trunk or stable version of boost so I don't know if this have any meaning. Joel Lamotte
On Sun, Apr 7, 2013 at 11:52 PM, Klaim - Joël Lamotte <mjklaim@gmail.com>wrote:
it don't work with gcc4.8: http://liveworkspace.org/code/4j9pGu$1
To be precise: I mean that the assertion fails. Joel Lamotte
On Sun, Apr 7, 2013 at 10:48 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
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.
My understanding is that auto work = work_queue.back(); Here 'work' a copy of the back element, not a reference. Visual Studio and answers to this question http://stackoverflow.com/questions/7138588/c11-auto-what-if-it-gets-a-consta... seem to confirm that it is the intended behaviour of auto (which I have followed so far, so don't have much doubts but maybe I'm wrong). So to me the difference is that with the vector the 'work' object is copy-initialized while with WorkQueue it is just copied by assignation (as the documentation you quote state). I'm not sure to follow what kind of issue Boost.Thread would have with the code you quote?
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();
};
To be more precise: 'work_queue' is taken by reference, while 'promise' (which is a shared_ptr) is taken by copy, so yes. The promise is not copied. I cannot move it into the lambda because lambdas don't provide a syntax for this (yet). Which is why I had to use a shared_ptr even if I don't like to have to pay an allocation for this. Fortunately this will not impact my application performance. Joel Lamotte
participants (4)
-
Klaim - Joël Lamotte
-
Stefan Strasser
-
Vicente Botet
-
Vicente J. Botet Escriba