Boost logo

Boost :

From: Levente Farkas (lfarkas_at_[hidden])
Date: 2000-09-08 03:36:29

William Kempf wrote:
> > > locks like that we could place the locks on the heap.
> Thus 'm1.lock
> > > ()' becomes 'plk1 = new mutex::lock(m1)' and 'm1.unlock()'
> > > becomes 'delete plk1'. Ugly? Yes, but that could be considered a
> > > good thing, since it puts up a red flag that what we're doing is
> > > unsafe.
> >
> > this isn't likes to me. if we alread have a change to lock and
> unlock
> > explicitly why we make it so difficult.
> The same reason why you have c_str() instead of operator const char*
> () for basic_string. The added difficulty discourages the use, but
> doesn't prevent it when needed. In our case, there's an additional
> reason. The lock class allows us to do compile time checking on the
> lock status for things such as condition::wait(). This is a HUGE
> improvement on the interface.

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!
> > those who read the manual and
> > know what is the guard for probably always will use it (if
> possible),
> > and those who don't know what they are doing will be in trauble
> anyway.
> I've never liked arguments like this. If you can make it harder to
> do things wrong you should do so, even if it means some cases are a
> little harder to program. This is especially true if the performance
> and functionality remains constant, as it does here (give or take a
> few clock cycles).

I have to repeat myself.
choice 1. programers use auto-lock and in this case everything is the
          same as now since he don't call the lock/unlock function on
          the mutex, most case that will be the situation.
choice 2. use the muteces luck/unlock function but in this case the wait
          or any other place where the compile time check is not possible
          use runtime or don't perform check. in this case the programmer
          have to be more careful about design (thread, exception...),
          BUT he's got chance to do so!!! and it's a big difference from
          current situation.
this is the same argumnet as with c stream/file handling and c++ stream
classes/functions. it's recommended to use the c++ safe stream library,
BUT the user/programer CAN use the old functions if he likes it. the
result is that the current situation give a safe way without loose the
performance AND a not-so-safe way but with additional functionality.
> Uhmmm... I'd have to see a concrete example. Other than a slight
> performance hit I can think of no reason why the locks must overlap
> this way. The call to m1.unlock() could probably be safely moved to
> after the call to m2.unlock(), which allows nested locking constructs
> and simple use of the lock class. The cases where the locks
> absolutely must overlap in this manner are rare, at least in my own
> experience. Rare enough to not warrant a change here.

I don't wanna create a dummy example since in this case one can always
can find another solutiuon, but in a complex problem it's a real problem.
just imagine that you have to release the first lock since in the second
lock-block the operation takes long and you don't wanna hold the first
lock just because it's looks better (and can use an auto-lock).
> > everything is solvable, but the price ...
> Is very small. Especially when weighed against the benefits of
> safety.

if you've got right that functions can be depricated later, but if not
in the current case there is no way to turn out since no one can use
the lock/unlock functions.
> > anyway in an oop word, it obious to me if I've an object which can
> be
> > lock nad unlock than it have two function a lock nad an unlock.
> > why the stream classes wasn't designed to be a helper class to open
> > and close it ?
> The comparison is apples to oranges. Fail to open the stream and 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 small and
> obvious. Not so with mutex locks. Fail to lock a mutex and call
> condition::wait() and you've got undefined behavior (with a more
> complex requirement on this we could have this result in a runtime
> error, but this is dangerous because of my next point). Fail to
> unlock the mutex and you get a runtime error... a deadlock! This

the destuctor of a mutex can always unlock it (if it's locked).

> sort of runtime error is extremely difficult to diagnose and correct
> because of the sheer nature of threads. The cost of making mistakes
> is high enough that we MUST attempt to prevent as many mistakes as
> possible at COMPILE time, even if this means corner cases become
> slightly more difficult to deal with.

yes, and we can do so with auto-lock for everybody who use it, and the
others take the risk.
> > > We don't have to work around the problem here, we just have to use
> > > the lock in a different manner. Portable, relatively safe and
> > > strongly illustrates the dangers when used.
> >
> > I think it has nothing to do with portable. and the mt stuff is
> always
> > dangerous nad hard to debug and ...
> Which is precisely why a good mt interface will go out of its way to
> catch mistakes at compile time!

yes in cases where possible.

another point with ANY thread library, that most programmer don't would like
to change their frame of mind. I talk with our windows developer and most
of them just thinking in event, mutex, criticalsection (where this is not
the same as mutex) and semaphore, and it's hard to understand why we need
a mutex for a condition if they don't need ot for event etc...
so I suppose generally it's not a good idea to go too far from the 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 requirement from the
win32 word and they can argue with it, while the CV (with wait which requires
a mutex) is requirement form posix word.

ps. my goal is just to be good, safe and useful library, which will be used
and accepted by everybody (or most people). if the result will be a library
which used by expert but most programers will use the native functions or
many different library, than it makes no sence.
just my .2c

 -- Levente
 "The only thing worse than not knowing the truth is
  ruining the bliss of ignorance."

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