Boost logo

Boost Users :

From: Weston Markham (wmarkham_at_[hidden])
Date: 2003-10-21 19:28:53

Mark, (and group)

I may not have explained myself clearly in my original message. Your
example ThreadedQueue::bMessageAvaliable() const actually demonstrates
_exactly_ why I feel that condition::wait should be const. Your method
modifies something internally (a boost::mutex; I have no argument whatsoever
with the view that locking a mutex changes its state). Then it does some
other things that don't affect its const-ness. Then it undoes the
modifications it originally made. (By unlocking the mutex)

A caller of this function should not care that these things go on
internally. In this sense, it is logically const. I would also add that
the caller of the function does not care that the precise behavior (say,
when it returns, or in other examples, the exact value that it does) of the
function can depend on the actions of other threads; this is the point that
I had expected resistance on.)

Similarly, the condition::wait will modify a mutex (unlocking it, and yes,
through a non-const Lock object). It will do some other stuff. Bookkeeping
or whatever, maybe even blocking itself. No matter what it does internally,
by the time it returns control to its caller, all of this has been undone.
The thread is not blocked. It is not in a waiting queue. The mutex that we
pointed it at has been locked again. From the caller's perspective, the
only things different after the call are:

1. Time has passed.
2. Some other threads have done some things that they might not have done
otherwise. What they do is their own business. I don't see how that can
affect this function's const-ness. (Am I missing something _here_?)

My conclusion is that condition::wait is logically const. I will certainly
admit that const-ness may be in the eye of the beholder. I expect that the
physically const vs. logically const is a problem with some people.
However, there do seem to be other examples of functions that are const (in
their signatures) in the same spirit that my intuition tells me
condition::wait is.

Does this elucidate my position?

Weston Markham

Mark Sizer wrote:
The condition wait() requires a lock, which requires a mutex. The mutex
state is toggled from acquired to free to acquired whilst the wait() is

It's the same problem that having a lock creates on a method such as
this one:

ThreadedQueue::bMessageAvailable() const
   { boost::mutex::scoped_lock( _mutexQueue )
     return !_queue.empty();

The only way to make that work is to declare the _mutexQueue as "mutable".

In the case above, I agree with you: In terms of logical "const-ness",
these methods are (or can be) const. In terms of physical "const-ness",
they are not. Solve the problem with "mutable".

However, the condition case is a bit more subtle.

ThreadedQueue::messageNext() const
   { boost::mutex::scoped_lock lockQueue( _mutexQueue );
     if ( _queueOut.empty() )
       // (the lock is released before blocking,
       // then re-locked before continuing)
       _conditionMessageReady.wait( lockQueue );
     // get a message

Is that really const? if the _mutexQueue and _conditionMessageReady are
made "mutable" we can MAKE the method const (as shown), but is it?

I'd say there is a EXPLICIT state change in the object: Into the waiting
state. This is a change, therefore non-const. In the bMessageAvailable()
case, there is no explicit state change, you're returning the existing
state of the object. There is an implicit state change required to
safely do so, which we've decided to hide. The only way this can block
forever is bad coding - deadlock.

When using a condition.wait(), you are making 2 big state changes:
  Both the object and the thread involved go from a "running" state into
a "blocked" state, perhaps forever if nothing notifies (which is
reasonable if the event never occurrs, not a coding deadlock error).
That doesn't seem "const" to me.

- Mark

Boost-users list run by williamkempf at, kalb at, bjorn.karlsson at, gregod at, wekempf at