0

I've read http://scottmeyers.blogspot.com/2013/03/stdfutures-from-stdasync-arent-special.html but it doesn't show an example of how one can implement the same kind of behavior - i.e. a future that will block in destructor same as the one returned from async but without using any async.

Can you please give such an example? Thanks!

zero323
  • 322,348
  • 103
  • 959
  • 935
xor256
  • 197
  • 9

2 Answers2

1

If you follow the comment thread underneath that article, you would see that other experts do not agree:

  • That futures which are not from async should block in the destructor.

  • With Scott Meyers interpretation of the standard that it should be the case.

Martinho Fernandes:

I don't see why this is a requirement for all futures: this particular requirement you quote is from the requirements upon std::async, not the requirements on std::future. The only requirement on the destructor of std::future is that it "releases the shared state". It happens that the shared state from std::async adds the requirement you quote, but no other shared state in the standard library has such a requirement.

Herb Sutter:

tl;dr: Martinjo already answered this correctly -- the article is not correct, the blocking applies only to futures returned from std::async with launch policy launch::async.

Scott said: and in 30.6.8/5, we see that [...] This is a requirement for any future object, not just the ones returned from std::async calls.

This does not follow. 30.6.8 is the specification of std::async. Anything said in there is specific to std::async.

But as Martinho already correctly said, this exception is in clause 30.6.8 "Function template async" only, and does not apply to futures in general.

Conclusion: I do not think you will be able to find the example you are looking for.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • Thanks! Am I correct than that to implement similar behavior I would have to create smth like the folowing `struct SharedState {~SharedState() { thread th()[] { while (true); }); th.join(); } };` and the use it in future as `future f;`? – xor256 Nov 28 '18 at 19:03
  • @xor256: Not sure what you are trying to do. But the code as you have given will not compile. – P.W Nov 29 '18 at 05:34
  • This is a pseudocode. ;) I'm trying to understand how can async implement a future that will block in destructor. Since it is shared state which is actually released I've assumed that the only way it can do it is to create a future with a SharedState which will wait in destructor for a thread (in an example infinitely). So I was trying to come up with an example where SharedState in destructor creates a thread which never finishes an joins it -> such future IIUC when returned from a function will block in destructor. – xor256 Nov 29 '18 at 18:49
  • @xor256: Implementation of async: You can read this question and answers for more info. https://stackoverflow.com/questions/25673475/how-is-stdasync-implemented. Some interesting info about async and future from this paper from Herb Sutter. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3630.pdf – P.W Dec 01 '18 at 11:35
  • Thanks for the link! Still I don't see an answer to my question there. So I've made up an example which compiles: https://pastebin.com/NDhuUHbu. Is this somewhat similar to async implementation? – xor256 Dec 05 '18 at 06:38
  • Different compilers do it differently. For GCC you can check this out: https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a00879.html – P.W Dec 05 '18 at 07:21
  • Thanks. This really looks similar `~_Async_state() { _M_thread.join(); }` – xor256 Dec 06 '18 at 23:19
  • @xor256: You are welcome. I hope this means your question is answered. – P.W Dec 07 '18 at 06:13
0

Sorry for answering to myself, but just to confirm that the question is answered: as per https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a00879_source.html it is indeed the shared state destructor that blocks not the future itself.

  template<typename _Res>
     class __future_base::_Async_state : public __future_base::_State
     {
     public:
       typedef _Res _Res_type;

       explicit 
       _Async_state(std::function<_Res()>&& __fn)
       : _M_result(new _Result<_Res>()), _M_fn(std::move(__fn)),
     _M_thread(mem_fn(&_Async_state::_M_do_run), this)
       { }

       ~_Async_state() { _M_thread.join(); }

And the future returned from async happens to use this exact kind of state. The same behavior can be achieved by creating a class which destructor will join() on some thread and creating a future with this class as template parameter: https://ideone.com/5RAPoA

xor256
  • 197
  • 9