
Howard Hinnant wrote:
On Jul 22, 2004, at 9:41 AM, Michael Glassford wrote:
I agree 100%, though I've spelled deferred_t as defer_lock_type and added try_lock_type. Thanks. You can now: scoped_lock lk1(m, defer_lock); // not locked scoped_lock lk2(m, try_lock); // tries to lock
If you remember, I proposed something along these lines (at the suggestion of Vladimir, IIRC) and liked it a lot, but changed my mind when it was pointed out that it prevents making the choice at run time whether the lock should be locked or not. With movable locks, as you point out below, this is changed somewhat.
Sorry, my acknowledgment list has gotten so confused I didn't even attempt one in the latest spec. The thread has gotten so long I'm forgetting who's proposed what, and have not taken the time to read back and check.
I'm not worried about that; I've forgotten who said what myself. I just wondered if you remembered that it had come up before. For what it's worth, I believe my final proposal looked as follows (the items marked "-" are possible constructors that I intentionally rejected): ScopedLock ---------- lock(m) lock(m, unlocked) - lock(m, locked) - lock(m, locked, blocking) - lock(m, blocking) ScopedTryLock ------------- - try_lock(m) //locked, blocking try_lock(m, unlocked) try_lock(m, blocking) try_lock(m, non_blocking) - try_lock(m, locked, blocking) - try_lock(m, locked, non_blocking) ScopedTimedLock --------------- - timed_lock(m) //locked, blocking timed_lock(m, unlocked) timed_lock(m, blocking) timed_lock(m, non_blocking) timed_lock(m, t) - timed_lock(m, locked, blocking) - timed_lock(m, locked, non_blocking) - timed_lock(m, t, locked) - timed_lock(m, t, locked, blocking) - timed_lock(m, t, blocking)
I've gone with: mutex_type* mutex() const; I don't have very strong feelings on this one, except that the current boost design does not hide the mutex interface as we thought it should. You just get to the mutex interface via the lock instead of directly. So I'm not that anxious to make it difficult to access the mutex and operate on it directly. Sometimes there's good reason to do that.
What can you do to a mutex except lock it with a lock object?
My comments were based on the fact that currently the mutex interface is private except for construction and destruction. This is meant to encourage the programmer to use the mutex only in an orderly (RAII) fashion.
<soapbox> However we do not currently prohibit code such as the following:
typedef mutex::scoped_lock MyMutex; mutex m; MyMutex my_mut(m, false);
void foo() { my_mut.lock(); }
void bar() { my_mut.unlock(); }
int main() { foo(); bar(); }
No, but the lock still unlocks when it goes out of scope and the mutex doesn't, which is some difference. Do you know of a way to prohibit such code?
I.e. It is not difficult to make a lock look exactly like a mutex with public member functions, and then use it in whatever way (orderly or not) you want to. Given that, perhaps it is better to just make the mutex interface public in the first place,
I don't agree.
and expose the mutex of a lock. Afterall, there are legitimate uses for locking and unlocking a mutex in a non-RAII pattern, and there are legitimate uses for needing access to a lock's mutex. The tools should not get in the way of the coder in the name of trying to save the coder from his own stupidity. Otoh, a good tool will make it easy to avoid stupid mistakes and write correct, efficient and elegant code. It is always a delicate line to walk when designing an interface. </soapbox>
Another possibility is to name the second parameter as an adjective describing the initial state of the lock instead of a verb:
scoped_lock l(m, unlocked);
scoped_lock l(m, tried); // ? scoped_lock l(m, Heisenberg); // ? :-)
scoped_lock l(m, non_blocking); Mike