Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2003-02-12 13:02:31


William E. Kempf wrote:
> Sorry for late reply... had a hard disk problem that prevented
> accessing e-mail.
>
> Peter Dimov said:
>> William E. Kempf wrote:

[...]

>>> void operator()()
>>> {
>>> mutex::scoped_lock lock(m_mutex);
>>> if (m_result)
>>> throw "can't call multiple times";
>>
>> operator() shouldn't throw; it's being used as a thread procedure,
>> and
>> the final verdict on these was to terminate() on exception, I
>> believe.
>> But you may have changed that. :-)
>
> I'm not sure how the terminate() on exception semantics (which haven't
> changed) apply, exactly.

Operator() should not report errors with exceptions because no one could
possibly listen. It's being executed in a separate thread, and if an
exception escapes, terminate() will be called.

In my example, I omitted the try block in operator() since I didn't want to
implement the exception translation logic, but such a try block is
necessary. Thread procedures effectively have a throw() specification.

> But I assume you (and probably Dave) would
> prefer this to just be an assert and documented undefined behavior. I
> have no problems with that.

I would prefer a second call to either complete, overwriting the result, or
to be silently ignored.

>>> R result() const
>>> {
>>> boost::mutex::scoped_lock lock(m_mutex);
>>> while (!m_result)
>>> m_cond.wait(lock);
>>
>> This changes result()'s semantics to "block until op() finishes";
>> what happens if nobody calls op()? Or it throws an exception?
>
> Changes the semantics? I thought this was what was expected and
> illustrated in every example thus far?

No, my example throws an exception when the call hadn't been made. It would
also throw when the call has been made but did not complete due to an
exception, had I added a try block in operator() that eats the exception.

>>> future(const future<R>& other)
>>> {
>>> mutex::scoped_lock lock(m_mutex);
>>
>> I don't think you need a lock here, but I may be missing something.
>
> I have to double check the implementation of shared_ptr<>, but I was
> assuming all it did was to synchronize the ref count manipulation.
> Reads/writes of the data pointed at needed to be synchronized
> externally.

Yes, you are right. The lock is necessary to achieve the level of thread
safety that you implemented. I think that a "thread neutral" (as safe as an
int) future<> would be acceptable, since this is the thread safety level I
expect from lightweight CopyConstructible components, but that's not a big
deal.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk