|
Boost Users : |
From: William E. Kempf (wekempf_at_[hidden])
Date: 2003-05-14 15:34:45
Christopher Currie said:
> This question sparked another "usage convetion" question in my memory
> that came up around the office lately. I've been slow introducing the
> members of my development team to a subset of Boost.Threads and trying
> to get them to use RAII thinking when implementing their locks.
>
> There seem to be two schools of thought on how to synchronize access to
> a class. One school, primarly from the developers who have experience in
> Java, tend to write classes that do their own mutex locking:
Please note that Java allows both types of synchronization to objects.
> class CalleeLocked
> {
> private:
> typedef boost::mutex mutex_type;
> mutex_type m_mutex;
>
> public:
> void synchronizedFunction() {
> mutex_type::scoped_lock lock( m_mutex );
> // ... do work ...
> }
> };
>
>
> The other school, to which I must admit I belong, believes that it
> should be the caller's responsibility to perform the locking:
>
> class CallerLocked
> {
> public:
> typedef boost::mutex mutex_type;
>
> void unsynchronizedFunction()
> {
> // ... do work ...
> }
>
> mutex_type & myMutex()
> { return m_mutex; }
>
> private:
> mutex_type m_mutex;
> }
>
> void Caller( CallerLocked & c )
> {
> CallerLocked::mutex_type::scoped_lock lock( c.myMutex() );
> c.unsynchronizedFunction();
> }
>
>
> The Callee lockers believe that is more important for the class to
> implement the locking, because the class knows what data it has that
> requires synchronized access, and that putting the locking inside the
> class means that you only have to get it right once. The Caller lockers
> argue that adding locks to all your class functions introduces overhead
> that is unnecessary if you never share instances between threads, and
> that making the locking explicit in the caller makes it somewhat easier
> to prevent, or at least track down, deadlock errors.
With the exception of accessing external, global data, inside a class
method, if any of the data needs protecting, all of it does. So I'm not
sure I agree with that argument.
The argument about added overhead, even when not accessed by multiple
threads, is a legitimate concern. There's a design pattern for this,
where the mutex type used is a template parameter and a "null mutex" which
does no synchronization can be chosen in cases where there will be no
sharing.
I'm not sure I agree that making the locking explicit at the call site
will make it any easier to prevent or track down deadlock errors.
A bigger issue with internal locking that you've not mentioned is that
this approach limits the granularity of the lock to the method call. This
is one reason why Java supports both types of synchronization. Andrei
Alexandrescu has a nice article on this very subject at
http://www.informit.com/isapi/product_id~{E3967A89-4E20-425B-BCFF-B84B6DEED6CA}/session_id~{021CB913-CD4D-49C4-9B32-4240CC8BA93C}/content/index.asp.
-- William E. Kempf
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net