Open this wandbox
(b, b, b,
b).
It contains an almost-complete implementation of my::future<T>
for object types (i.e. not void or reference types).
Your task is to implement future_shared_state::set_ready()
and
future_shared_state::set_continuation()
.
set_ready
needs to do the following things:
m_ready=true
.m_cv.notify_all()
to wake up the waiting future (if any).m_then()
, if it is non-empty.set_continuation
needs to do the following things:
continuation()
and return.m_then = continuation
.set_continuation
is called from future::then
,
and set_ready
is called from promise::set_value
.
So, to avoid a race between set_continuation
's read and set_ready
's write,
both functions must deal with m_then
under a mutex lock. (You should use
m_mtx
for this purpose.)
But you must not call m_then
under the mutex lock! Why not?
Use our -DX=std::this_thread::sleep_for(1ms);
trick to test your implementations.
Do they really work?
If your solution involves running m_then()
while still holding the mutex lock,
that's probably a problem.
Consider that even running something as trivial-looking as
m_then = std::move(continuation);
will call the move-constructor of
unique_function<void()>
, which could call the move-constructor of
any T
that has been captured inside the unique_function
.
Is this a problem? How could we solve it? (This is an open question, as far as I know.)
You're done with the seventh set of exercises! Sit back and relax, or optionally, browse the following links.