Boost logo

Boost :

From: Scott McCaskill (scott_at_[hidden])
Date: 2001-09-14 14:08:01


I think there are definitely some cases where free functions make more sense
than member functions, like condition::wait and thread::join. When I see
something like the following pseudocode:

thread t(someFunctionObject);
t.join();

..this looks like t is doing the joining, rather than _being_ joined. OTOH:

join(t);
or, better:
wait(t);

This looks more like what it does (er, would do:)--the calling thread waits
for t to finish execution.

I also don't see a problem with using the name 'wait' in more places. Re.
thread::join(), I have often heard the argument that 'join' is preferable
for historical reasons. However, I think this argument overlooks the fact
that (IMO) once one understands multithreaded programming _concepts_, the
names are relatively less important. So someone who knows what it means to
join a thread will have little trouble realizing that something like
ait( thread ) does the same thing. OTOH, for someone with less previous
experience, the name 'wait' is more true to the intent of the function.
When I think of joining another thread, I think of waiting for that thread
to finish. Yes, resources are also reclaimed, but that seems much more like
an implementation detail or at most a side effect.

wait( thread ) -- wait for a thread to finish
wait( condition, lock ) -- wait for a condition to be signaled
wait( semaphore ) -- I'm not so sure about this one. I have also seen
increment/decrement, and acquire/release. I'm rather partial to
acquire/release, since I think of a semaphore primarily as something used to
grant access to a limited number of resources, and I think of the actual
count (and the potential wait) as more of an implementation detail.
wait( xtime ) -- wait until the specified time (i.e. sleep)

I'd like to write a longer reply, but unfortunately I don't have time. So
I'll just sum up by saying that I agree with much of what Ed has said.

BTW, I'm very glad to see that boost.threads has been accepted--it's great
to finally have a portable and easy to use thread library. Excellent work!

----- Original Message -----
From: "Ed Brey" <edbrey_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, September 14, 2001 10:05 AM
Subject: Re: [boost] Re: Review: Boost.Threads

> From: <williamkempf_at_[hidden]>
>
> > > I agree with you that blocking can be viewed as a side effect of
> > waiting on a condition. But given this view, the function is named
> > for its side effect, rather than its primary effect of locking and
> > unlocking the mutex. In addition, it isn't the condition that waits,
> > it's this_thread, but waits membership in condition implies
> > otherwise. I see two consistent approaches that can be taken: (1)
> > keep the function a member of condition and call it unlock_then_lock,
> > or something less, or arduous, or (2) make it a free function and
> > call it wait. In the latter case, blocking would be considered the
> > primary effect and unlocking and locking would be considered side
> > effects. Each view is equally valid. The second seems focus more on
> > the effects that the user cares about.
>
> > You're thinking a little too low level here (and I don't know if
> > thinking about it at the proper level will change your mind, but we
> > need to get up there to discuss this). The locking and unlocking are
> > side effects of waiting, not the primary functionality, nor what
> > causes the thread to block (though the locking could extend the
> > length of time that the thread blocks). The actual action is that of
> > the condition object waiting for a signal that some state has changed.
>
> I agree completely (except for the first line ;). I also favor calling
function that waits on the condition variable "wait". The issue is that
since it isn't the condition object that does the waiting, the function
should not be a member of condition. The only reason I mentioned approach 1
above was to demonstrate what the function would need to be called in order
to consistently be a member of condition. However, we both agree that such
a view is too low level and would obscure the main functionality of the
function.
>
> > > Certainly not every function that blocks (waits) should be called
> > wait. Wait is only a good name if waiting is the primary (or only)
> > effect. For example, istream::open, printf and semaphore::decrement
> > open, print and decrement, plus block as a side effect, whereas wait
> > (xtime) just waits, wait(thread) just waits, and wait(condition,
> > lock) waits, plus has a side effect.
> >
> > That's awfully subjective. What's a side effect and what's not?
> > What does mutex.lock() or semaphore.up() do that's not a side effect
> > thus eliminating them from candidates for wait(mutex) and wait
> > (semaphore)?
>
> Absolutely it's subjective. Fortunately, it also seems clear-cut enough
that a consensous on what is the primary effect is easily reached. For
example, we both agree that when waiting on a condition, waiting is the
primary effect and locking is a side effect. In the case of
mutex::scoped_lock::lock, I'd say that locking (i.e. guaranteeing exclusive
access) is the primary effect, and blocking is an undesireable but necessary
side effect needed to accoplish it. For semaphore, both the waiting and
signalling are important, but perhaps we can all agree on the reasonable
view that incrementing and decrementing are the primary effects, and
blocking is a side effect. What do you think?
>
> > Actually, join() does more than wait for the thread to finish. It
> > also cleans up all resources associated with that thread. It's akin
> > to fstream::close() in this regard. But this is a different argument
> > from the one in this current discussion.
>
> I'm confused by this. Your documentation for join says that the only
effect is to block. The reference to resources being reclaimed speaks only
to how long the blocking lasts. This seems quite different that
fstream::close(), where the file wouldn't be closed had the function not
been called. With threads, the thread will terminate and be cleaned up
whether join is called or not (according to my understanding of your
documentation). Is there something I'm misunderstanding?
>
> > To me this just further shows how this concept is too ambiguous.
> > Given the name "wait" you and I have completely different notions of
> > what to expect. Given the name "sleep" we both have a clear
> > understanding of what to expect.
>
> For discussions like this, terms like sleep and join are great because
they concisely separate different actions. It's just like if we were to
discuss the various overloads of vector::insert, we may wish to have concise
terms to discuss insert range, insert element, and insert copies of element.
But once the discussion is done, those terms turn into baggage because the
scope changes from focusing on a small area of a library to writing an
entire program using many libraries, and each new name and concept has a
ramp-up cost. Therefore, if we can bundle like concepts into a group, but
make their actions clear and distinct by overloading, we've made the library
more usable. I think that there is a good potential for this in the thread
library, and when taken as part of a consistent interface, no one will get
confused if they see wait(timeout), and think it is going to return
immediately. The value gained is that rather than presenting a series of
fairly unrelated functions, !
> we can present the "wait family of functions", all of which have waiting
as a primary effect and all of which have a common convention for specifying
(or not) a timeout.
>
>
>
> Info: http://www.boost.org Unsubscribe:
<mailto:boost-unsubscribe_at_[hidden]>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>
>


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