
On Jul 15, 2004, at 7:42 PM, Matt Hurd wrote:
I'm not sure I see the case for deferring anything a stack based scoped lock with a: void folly () { { scoped_lock l(m); do_stuff(); }
{ scoped_lock l(m); do_more_stuff(); } } is still preferable to me than allowing explicit locking of a lock.
I have a couple of places where I need a "deferred" lock: Namely I have 2 generic templated lock classes that take other locks as template parameters, and store references to those locks: template <class Lock1, class Lock2> class transfer_lock; template <class Lock1, class Lock2> class lock_both; The constructor for transfer_lock takes two locks, referencing the same mutex, the first of which must be unlocked, and the second locked. The constructor for lock_both takes two locks, referencing different mutexes, both of which must be unlocked. Example use: mutex m; scoped_lock lock1(m1, deferred); // or whatever syntax for not locking scoped_lock lock2(m2, deferred); lock_both<scoped_lock, scoped_lock> lock(lock1, lock2); // m1 and m2 atomically locked here, without fear of deadlock Without the ability to construct but defer locking of lock1 and lock2, the construction of lock_both becomes inefficient and awkward.
I worry about paying for the overhead, perhaps in space for a scoped time lock that records it timing versus a blocking lock that needs no such information, but I'm not sure that it is a big deal as the difference is negligible and these will typically be stack based. Implementation will reveal all I guess.
There is no overhead in the lock types, at least with the current boost design. All locks I've coded contain a reference to the mutex, and a bool indicating locked status (even the read_lock, write_lock and upgradable_read_lock). But there is overhead in the mutex types, and it can vary significantly among the different types: (basic, try, timed, recursive, read/write). Sometimes the overhead is on the stack, sometimes not (depends on the OS and on the mutex implementation). Here is a sample survey of sizeof() on one of my platforms I need to support: sizeof(mutex) = 44 sizeof(try_mutex) = 44 sizeof(timed_mutex) = 76 sizeof(recursive_mutex) = 44 sizeof(recursive_try_mutex) = 44 sizeof(recursive_timed_mutex) = 80 sizeof(rw_mutex) = 108 On another platform it looks like: sizeof(mutex) = 44 sizeof(try_mutex) = 44 sizeof(timed_mutex) = 76 sizeof(recursive_mutex) = 80 sizeof(recursive_try_mutex) = 80 sizeof(recursive_timed_mutex) = 80 sizeof(rw_mutex) = 108 On a third platform I support there are differences between mutex and try_mutex, but the difference is not well illustrated by sizeof() because the "mutex type" is just a 4 byte handle in some cases (but not others). sizeof(mutex) = 24 sizeof(try_mutex) = 4 sizeof(timed_mutex) = 4 sizeof(recursive_mutex) = 24 sizeof(recursive_try_mutex) = 4 sizeof(recursive_timed_mutex) = 4 sizeof(rw_mutex) = not implemented And of course all of this is subject to change. But if I'm forced to include all capability into one mutex type, then there is definitely going to be a price paid on some platforms by those who only want a mutex (which is also by far the most often needed type). -Howard