
Howard Hinnant wrote:
On Aug 21, 2007, at 7:34 PM, Yuval Ronen wrote:
All this complexity is simply unnecessary, IMO. You can drop the lock/try_lock/unlock functions from the locks, keep them for mutexes, and declare that std::lock/scoped_lock/unique_lock work only for mutexes. You can then drop defer_lock also, and everything is much simpler...
Consider a use case where the mutex, but not the lock has been encapsulated away, and you want to unlock the lock prior to its destruction:
typedef std::mutex Mutex;
Mutex& get_mutex() { static Mutex mut; return mut; }
typedef std::unique_lock<Mutex> Lock;
Lock get_lock() { return Lock(get_mutex()); }
typedef std::condition<Mutex> Condition;
Condition& get_condition() { static Condition cv(get_mutex()); return cv; }
void foo() { Lock lk = get_lock(); change_data(); if (some_flag) { lk.unlock(); // <--------- here get_condition().notify_all(); } }
Instead of lk.unlock(), we can write lk.get_mutex().unlock(), for example. Another option is to say that encapsulating away the mutex is not a valid use case. Remove the get_lock() function and write: void foo() { Mutex &m = get_mutex(); Lock lk(m); change_data(); if (some_flag) { m.unlock(); get_condition().notify_all(); } } I don't see any benefit in encapsulating the mutex. Just like unique_ptr<T> doesn't encapsulate the T.
Question 10 shows a motivating use case for defer_lock that does not involve the member lock/unlock functions on locks.
It does involve them, even though not directly. If we remove lock/unlock, then there is no reason for unique_lock to have a 'bool owns' data member. The ownership is detemined by null-ness of the 'mutex_type* m' data member. And now the second return statement in Q.10 (the 'else' part) can be replace with 'return std::unique_lock<std::mutex>()'. No need for defer_lock.