[future N2561] Implementation comments

Hi, on the current Future (N2561) library proposal the promise protect the value setting/getting from multiple threads using a lock, but the lock do not protect the future initialization (lazy_init()). void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); boost::lock_guard<boost::mutex> lock(future->mutex); if(future->done) { throw promise_already_satisfied(); } future->mark_finished_with_result_internal(r); } I'm wondering if we don't need to extend the protection or avoid the lazy initialization? I'm missing something? BTW, Is it safe to take the address of a promise? If not, why not delete the operator&()? Best, Vicente

"vicente.botet" <vicente.botet@wanadoo.fr> writes:
on the current Future (N2561) library proposal the promise protect the value setting/getting from multiple threads using a lock, but the lock do not protect the future initialization (lazy_init()).
void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); boost::lock_guard<boost::mutex> lock(future->mutex); if(future->done) { throw promise_already_satisfied(); } future->mark_finished_with_result_internal(r); }
I'm wondering if we don't need to extend the protection or avoid the lazy initialization? I'm missing something?
Concurrent calls to set_value are not supported with this implementation. The mutex is there to protect concurrent calls to unique_future::get() and promise::set_value(). Protection of lazy_init would require a different mechanism, such as the use of boost::call_once.
BTW, Is it safe to take the address of a promise? If not, why not delete the operator&()?
Yes, it's safe. If someone move-assigns it you might not be associated with the same result you thought you were, but it's safe. Anthony -- Anthony Williams Author of C++ Concurrency in Action | http://www.manning.com/williams Custom Software Development | http://www.justsoftwaresolutions.co.uk Just Software Solutions Ltd, Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK

----- Original Message ----- From: "Anthony Williams" <anthony.ajw@gmail.com> To: <boost@lists.boost.org> Sent: Wednesday, December 03, 2008 11:17 AM Subject: Re: [boost] [future N2561] Implementation comments
"vicente.botet" <vicente.botet@wanadoo.fr> writes:
on the current Future (N2561) library proposal the promise protect the value setting/getting from multiple threads using a lock, but the lock do not protect the future initialization (lazy_init()).
void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); boost::lock_guard<boost::mutex> lock(future->mutex); if(future->done) { throw promise_already_satisfied(); } future->mark_finished_with_result_internal(r); }
I'm wondering if we don't need to extend the protection or avoid the lazy initialization? I'm missing something?
Concurrent calls to set_value are not supported with this implementation. The mutex is there to protect concurrent calls to unique_future::get() and promise::set_value().
Ok, I see. Do we need to set_value from different threads? Should the promise::set_value() be thread safe or not? What says the C++0x standard?
Protection of lazy_init would require a different mechanism, such as the use of boost::call_once.
Why not?
BTW, Is it safe to take the address of a promise? If not, why not delete the operator&()?
Yes, it's safe. If someone move-assigns it you might not be associated with the same result you thought you were, but it's safe.
I was not talking of move-assigning but to take the address which preserve the promise contents and is dangerous if concurrent calls to set_value are not supported with this implementation. So, why not delete the operator&()? Vicente

"vicente.botet" <vicente.botet@wanadoo.fr> writes:
Ok, I see. Do we need to set_value from different threads? Should the promise::set_value() be thread safe or not? What says the C++0x standard?
The C++0x draft standard is silent on the matter. I think it probably
Protection of lazy_init would require a different mechanism, such as the use of boost::call_once.
Why not?
The existing lock uses future->mutex. Until lazy_init is called for the first time, future is a NULL pointer, so we can't use future->mutex. You could use a second mutex to protect the future pointer, but it would be unnecessary locking after the first call (or the first call after a move).
BTW, Is it safe to take the address of a promise? If not, why not delete the operator&()?
Yes, it's safe. If someone move-assigns it you might not be associated with the same result you thought you were, but it's safe.
I was not talking of move-assigning but to take the address which preserve the promise contents and is dangerous if concurrent calls to set_value are not supported with this implementation. So, why not delete the operator&()?
Just because something is not thread safe does not make it appropriate to delete the operator&. You can pass things around by pointer without making them accessible to more than one thread, and you can pass things by reference that ARE accessible by more than one thread, even if that isn't safe. Anthony -- Anthony Williams Author of C++ Concurrency in Action | http://www.manning.com/williams Custom Software Development | http://www.justsoftwaresolutions.co.uk Just Software Solutions Ltd, Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK

----- Original Message ----- From: "Anthony Williams" <anthony.ajw@gmail.com> To: <boost@lists.boost.org> Sent: Wednesday, December 03, 2008 2:18 PM Subject: Re: [boost] [future N2561] Implementation comments
"vicente.botet" <vicente.botet@wanadoo.fr> writes:
Ok, I see. Do we need to set_value from different threads? Should the promise::set_value() be thread safe or not? What says the C++0x standard?
The C++0x draft standard is silent on the matter. I think it probably
So the idea is that a promise should be used only by a thread. Right?
Protection of lazy_init would require a different mechanism, such as the use of boost::call_once.
Why not?
Sorry, I would like to say why not!
I was not talking of move-assigning but to take the address which preserve the promise contents and is dangerous if concurrent calls to set_value are not supported with this implementation. So, why not delete the operator&()?
Just because something is not thread safe does not make it appropriate to delete the operator&. You can pass things around by pointer without making them accessible to more than one thread, and you can pass things by reference that ARE accessible by more than one thread, even if that isn't safe.
You are right. It is enough to state that this is not thread safe. Thanks for all, Vicente

"vicente.botet" <vicente.botet@wanadoo.fr> writes:
From: "Anthony Williams" <anthony.ajw@gmail.com>
"vicente.botet" <vicente.botet@wanadoo.fr> writes:
Ok, I see. Do we need to set_value from different threads? Should the promise::set_value() be thread safe or not? What says the C++0x standard?
The C++0x draft standard is silent on the matter. I think it probably
So the idea is that a promise should be used only by a thread. Right?
Some of the proposed uses would require that set_value is thread-safe.
Protection of lazy_init would require a different mechanism, such as the use of boost::call_once.
Why not?
Sorry, I would like to say why not!
I don't understand. Please can you ask your question using other words. Anthony -- Anthony Williams Author of C++ Concurrency in Action | http://www.manning.com/williams Custom Software Development | http://www.justsoftwaresolutions.co.uk Just Software Solutions Ltd, Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK

Anthony Williams <anthony.ajw@gmail.com> writes:
"vicente.botet" <vicente.botet@wanadoo.fr> writes:
on the current Future (N2561) library proposal the promise protect the value setting/getting from multiple threads using a lock, but the lock do not protect the future initialization (lazy_init()).
void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); boost::lock_guard<boost::mutex> lock(future->mutex); if(future->done) { throw promise_already_satisfied(); } future->mark_finished_with_result_internal(r); }
I'm wondering if we don't need to extend the protection or avoid the lazy initialization? I'm missing something?
Concurrent calls to set_value are not supported with this implementation. The mutex is there to protect concurrent calls to unique_future::get() and promise::set_value().
Actually, thinking about it some more, and remembering the rationale, I'll revise that statement. Once a promise has an associated asynchronous value, it is safe to call set_value concurrently from multiple threads, since lazy_init is a no-op. If you call get_future() then this initialization is forced. Alternatively, it is trivial to add a call to lazy_init to the default constructor. If, however, you move the promise into another promise then it no longer has an associated asynchronous result, and must again be initialized before concurrent calls to set_value are safe. You can do this by moving a default-constructed promise into the promise in question, or calling get_future on it. It might be worth removing the lazy_init call from set_value and get_future in order to make this clear --- if you move from a promise, you have to move into it in order to use it again. Anthony -- Anthony Williams Author of C++ Concurrency in Action | http://www.manning.com/williams Custom Software Development | http://www.justsoftwaresolutions.co.uk Just Software Solutions Ltd, Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK
participants (2)
-
Anthony Williams
-
vicente.botet