Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-09-08 11:24:15

--- In boost_at_[hidden], Levente Farkas <lfarkas_at_m...> wrote:
> William Kempf wrote:
> > > that's not a good example, since on the interface THERE IS a
> > function
> > > for const char*, but in the mutex there si no lock!
> >
> > Oh yes, there is a lock, it's just not a function.
> yes and the code loose it's simplicity and clarity.

Debatable. Also irrelevant if you wrap the concept, as I did in
another post with the "unsafe_lock".

> > They don't NEED to. You've got to remember that. If explicit
> > lock/unlock is required than you create the lock on the heap. No
> > functionality lost, no performance lost.
> yes and the code loose it's simplicity and clarity.
> and most user won't use it, what's more I can cheet and call the
> function if I realy want it, but that's not what I want.

It's a good thing that most users won't use it. If a user absolutely
must have overlapping locks, he will use it. As for calling the
private functions... uhmm... not unless you hack the code. You don't
have access to the private functions. That's the whole point here.
> > > > The comparison is apples to oranges. Fail to open the stream
> > you
> > > > get obvious runtime errors. Fail to close the stream and
it'll be
> > > > closed for you at the time of destruction. The impact is
> > and
> > > > obvious. Not so with mutex locks. Fail to lock a mutex and
> > > > condition::wait() and you've got undefined behavior (with a
> > > > complex requirement on this we could have this result in a
> > > > error, but this is dangerous because of my next point). Fail
> > > > unlock the mutex and you get a runtime error... a deadlock!
> > >
> > > the destuctor of a mutex can always unlock it (if it's locked).
> >
> > class A
> > {
> > mutex mx;
> > public:
> > void foo()
> > {
> > mx.lock();
> > }
> > void bar()
> > {
> > mx.lock();
> > }
> > };
> >
> > A a;
> >;
> >; // Foo-barred indeed!
> class A
> {
> mutex mx;
> public:
> void foo()
> {
> mutex::lock lock(mx);
> bar();
> }
> void bar()
> {
> mutex::lock lock(mx);
> }
> };
> A a;

You've gone back to the "right" interface here. The point is, my
experience tells me that if you allow both interfaces programmers use
the unsafe interface when they shouldn't and wind up with the problem
I illustrated.

> > The problem domains are not the same between a stream and a mutex.
> > If mx had been a stream and we'd called open instead of lock we'd
> > have no real problem here. The second call to open could have
> > failed or closed the old file and the destructor would insure the
> > file was eventually closed. With the mutex, the same programming
> > error has instead lead to deadlock. Possibly disastrous deadlock.
> if the mutex is not recursive yes (although I vote against it many
> in this list), but if it's not recursive, the above code also suck.

Recursivity has nothing to do with this. foo() could have been
called in one thread and bar() in another to get the same results.
> > Maybe deadlock that only rarely occurs. Likely deadlock that's
> > difficult to debug and correct. No, it's apples and oranges and I
> > simply won't live with the danger. I think that anyone that's
> > extensive threaded programming would agree with me.
> I don't, just see the above simple example.

Which example? I'm a little lost here since we've both posted
several examples.
> > I've seen so many libraries designed this way. Even with good
> > documentation on the dangers I've found that most people who
> > using these libraries still use the explicit lock/unlock functions
> > when they should be using an auto-lock, and I've seen many a
> > occur because of this. My experience here is going to make me
> > hard headed about this. I will argue with you until you're sick
> > me about this one. I'm not in favor of exposing lock/unlock on
> > mutex itself.

Yes, it is. I have to use code written by those programmers. I have
to maintain code written by them. I have to help them figure out why
they're deadlocking. Why? Because they are my colleagues working on
a large project. We don't work in a vacuum.

> what if I make a subclass of mutex which have a lock and unlock
function ?
> do you wanna prevent this too ? you can't (if I can lock and unlock

It's already prevented, IMHO. Firstly, the lock/unlock that exists
in the mutex is private so you don't have access to them even if you
subclass. Secondly, there's not a virtual destructor so subclassing
is strongly discouraged. So, reasonable misuse is prevented. Yes,
you can still misuse things, but only by bending over backward, which
is then your problem, not mine.
> > And it's very much possible here. Why are you fighting me on that
> > point?
> you can't see the above subclass example.
> just beacuse I'm belive I'm right.

No, I can't see a subclass example, because you still have no access
to lock/unlock.
> > Uhmm... I'm a Windows programmer. I've never used the pthread
> > library (though I've studied it for academic reasons). I disagree
> > with you totally. They may have never seen a CV before, but a
> > explanation and a quick example and I bet the vast majority of
> > will have no problems understanding them or fail to see their
> > Most will probably even understand how they are superior to the
> > Windows event, which is the closest analog available to them.
> > most of them have probably coded a CV themselves!
> it seems to me that you realy just wanna argue with me.

No, it's not a matter of putting my back up. I simply don't agree
with what you said, and I gave cogent reasons why not.

> the above was not
> my opinion and I don't vote for this.

Then I'm very confused. You posted someone else's opinion? Well
then, I disagree with them, not with you.

> I just simple state the the
> higher level part of a thread library would have to support all
> platform's primitives if we'd like to be excepted by most people.
> actualy mutex and cv would be enough for me and monotor, rw-lock
and a
> few other at higher level.

I don't agree. Most reasonable programmers would not resort to using
platform specific types exclusively just because our library didn't
include them. This is especially true if the library were to someday
be part of the language standard.

> > As for not understanding why you need a mutex for a condition...
> > that's probably the most obvious thing to grasp after a condition
> > described. The atomic operation of unlock/wait/lock is an obvious
> > advantage over Win32 events.
> operation on event also atomic.

On the event, yes. But that's simply a wait operation, not a
unlock/wait/lock operation. Apples to oranges, and anyone that is
introduced to CVs should see this.
> > > so I suppose generally it's not a good idea to go too far from
> > current
> > > patterns, neither from win23 nor from posix. we have to support
> > primitives
> > > of both "platform". probably the win32 primitives will slower on
> > posix and
> > > vice versa. eg support for WaitForMultipleObject is a
> > from the
> > > win32 word and they can argue with it, while the CV (with wait
> > which requires
> > > a mutex) is requirement form posix word.
> >
> > Sorry, I disagree here. WFMO is a poor hack to work around the
> > of condition variables. The only case in which it's really
useful is
> > when waiting on multiple events, which is the same as waiting on
> > multiple predicates tied to a single CV, or when waiting on
> > threads to end, which can be done in so many different ways that
> > just a convenience function there.
> again, I agree with it, but those who use it used to use it and if
> got a library whithout it, they will say it's just a subset (without
> thinkink, cause they think in another way).

You're putting words into their mouths and making assumptions.
Again, I'm a Windows programmer exclusively. I've never touched
pthreads. I didn't react this way or think this way when I was
introduced to CVs and portable thread libraries. Personally, I doubt
that most people would react any differently than I did.
> > Win32 events really serve little purpose when you have CVs. They
> > also trivial to implement on your own. So, I don't think they
> > warrant consideration.
> that's why we have to implement it.

Have to? I don't think so. If we do, than why are we stopping
there? Why not gates as well? I'm sure there are numerous other
synch objects in use else where, so we need to include all of them.

No, if they are trivial to implement and don't really gain you
anything over the other synch objects I don't think they warrant

> > Critical sections are just faster mutexes (as well as not being
> > kernel objects, but that means a lack of functionality which
isn't a
> > reason to include them). Since I've shown a mutex written for
> > that's (nearly) as fast as a critical section, there's no reason
> > include it.
> I don't want to include it, but maybe a typedef for our mutex as
> critical section would help in a first place, later can be deleted.

Why? What's gained/lost/different? Again, the mutex in my
implementation is as fast (or at least close), has all the
functionality, plus it allows timed locks, portable try locks (the
critical section only has try locks on NT) and can be shared between
processes with minor alteration of the interface (that functionality
is still being discussed).

> > We've got analogs to the Win32 semaphore and mutex. The only
> > concepts we're really missing at this point and time are TLS and
> > MsgWait. TLS will be added in due course. MsgWait isn't very
> there is tls in posix too.

I know that. I wasn't trying to compare Win32 to posix, only list
the Win32 concepts that aren't currently in the Boost
documentation/concept code.
> > My goal is safety, flexibility, attention to C++ constructs,
> > standardization (it would be nice to eventual make it into the
> > language standard) and speed. I think we're well on the way
> > I don't see the interfaces as being "usable only by experts", and
> > fact think we've done the opposite... made advanced concepts
> > to use (correctly!) and understand by beginners.
> my other goal is to be clear, simple and small as my belive is if a
code is
> smaller (where the smaller is not depend on the name of the
variables and so)
> is better since it's more simple easier to read and can contain
less bug.

Then you should prefer the current interface as there are fewer
functions and no duplication of functionality while making it much
harder to write buggy code. Your proposed change to the interface
violates all of these additional criteria.

Bill Kempf

Boost list run by bdawes at, gregod at, cpdaniel at, john at