Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2001-09-24 05:57:09


From: "David Abrahams" <david.abrahams_at_[hidden]>
> From: "Peter Dimov" <pdimov_at_[hidden]>
>
> > The point is that overloading a name to mean different things in
different
> > contexts is not necessarily a good thing. An overloaded name implies
that
> I
> > don't care about the specifics of the call. I simply say x + y and
expect
> it
> > to do the right thing. Obviously, when I say wait(x) I do care about
which
> > 'wait' variation is being performed.
>
> Just as when you do std::cout << x you care about which streaming
variation
> is being performed... but there is a single way to stream that's
appropriate
> for each type you can use for x. Trying to remember a separate name for
each
> of the streaming operations just makes life harder.

No, I don't care about which streaming operation is being performed. That's
what makes writing templates like lexical_cast<> possible.

The Dimov Test for Appropriate Overloading (DTAO) ;-) is "can you answer the
questions below:"

template<class T> void f(T & t, U & u)
{
    std::cout << t; // what does this line do?
    wait(t); // ditto
    wait(t, u); // ditto
}

Aside: another application of the same rule:

template<class Lock, class Mutex> void f(Mutex & m)
{
    Lock l(m); // what does this line do?
}

> > The 'join' variation invalidates x;
>
> I think seeing it that way requires a kind of "manufactured ignorance"
that
> there is any threading. Join actually /waits/ for x to become invalid.

This is what I'd like it to do, but it's not what it presently does.
t.join() really does invalidate t, it doesn't wait and observe. Example:

t.join();
t.join(); // undefined behavior

vs

sleep(...); // t ends in the meantime
t.join(); // well defined behavior

> > I can't simply say wait(t) inside and trust it to perform the right kind
> of
> > operation. I have to know what t is, and if I do know that, why define
the
> > function as a template?
>
> Precisely. And how would having different names help with this situation?

Why should they help with it? What is the problem that you're trying to
solve?

> > (The Win32 API is a good example of why this kind of wait() overloading
> > doesn't really work.)
>
> Details, please.

From MSDN:

"The WaitForSingleObject function can wait for the following objects:

Change notification
Console input
Event
Job
Mutex
Process
Semaphore
Thread
Waitable timer"

The problem with this overloading is that given a generic HANDLE, you
shouldn't even think about Wait'ing on it; the Wait operation could acquire
the mutex, or have some other unexpected side effect.

The common name implies common semantics, which is not the case here. This
is lying to the user. The user will exact revenge. ;-)

> > Now if you refine the wait() semantics a little, saying that wait(e)
> blocks
> > the current thread until the event e occurs, and then provide a way to
> > specify a 'thread finished' event, a 'time reached' event, a 'predicate
is
> > true' event, I'll be inclined to agree with you.
>
> How does the above differ substantially from what we'd get if we just gave
> the current wait/sleep/join semantics the same name?

Here's a sketch:

wait(e);

Effects: blocks the current thread until the event e occurs.

wait(e, xt);

Effects: blocks the current thread until the event e occurs or the time xt
is reached, whatever happens first.

Returns: true if e has occured, false otherwise.

Now we need to define what 'event' means:

Event concept:

Operations:

wait(e);
wait(e, xt);

Open questions:

Do the above operations invalidate e? Change e?
Can I wait() several times in a row on the same event?
Is an Event CopyConstructible? Assignable? EqualityComparable?
LessThanComparable?
Is an Event a compile-time concept or a run-time concept?
If the latter, are all Events derived from a common AbstractEvent? Or is an
Event a handle to an AbstractEvent body?
Is a thread an event? Should it be?
Is an xtime an event? Should it be?
How can I convert a (condition&, predicate, mutex&) tuple to obtain an
event?

And several others that I'm sure somebody will come up with.

What I'm trying to say is that designing an uniform 'wait' layer is a
serious task, and simply adding three wait overloads is unlikely to achieve
the goal.

Another perspective: we have three categories of users:

1. Threading experts;
2. Pthread programmers;
3. Programmers with little or no thread experience.

The problem we're trying to solve, AFAICS, is that the current design does
not target (3). The proposed solutions so far concentrate on renaming
functions. Does this help?

Not much, I'd say. We need another, higher level, abstraction layer that is
specifically designed with (3) in mind. Let's leave the current low-level
design suitable for (1) and (2). Using standard POSIX names (and semantics)
is such a step.

--
Peter Dimov
Multi Media Ltd.

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