
On 11/29/2010 11:10 AM, Howard Hinnant wrote:
And in the ting version the last line looks like:
lk = unique_lock<upgrade_mutex>(move(ul));
I.e. The type-change must be called out explicitly. Perhaps it is just my paranoia, but this library is novel in its ability to change the ownership mode of the mutex, and so people may not be expecting it.
I had an upgradable lock class going years ago and I found it quite handy. I'm looking forward to using this next time I need it.
So I'm trying to make the change of ownership explicit.
Always a good thing. The facility I used did not use have a different lock type for 'upgradable', all shared locks were upgradeable (of course we called them read and write locks). An upgrade operation would always succeed if you were willing to wait long enough. The way the deadlock issue was handled was simple: it didn't guarantee that the upgrade would be performed atomically in every case. Sometimes a different thread would get his exclusive ownership in between your shared and exclusive locks. Of course, whether or not your upgrade happened atomically was indicated in the return value. This allowed a common pattern: shareable_mutex g_mut; // Ensure color is made blue, if it isn't already. // get_color() and set_color() are nontrivial operations. void ensure_blue() { lock l(g_mut, shared, forever); if (get_color() != blue) { bool upgrade_was_atomic = l.upgrade_to_exclusive(forever); if (upgrade_was_atomic || get_color() != blue) set_color(blue); } } So the code didn't need to call get_color() twice when the lock was upgraded atomically. That was the usual case. I'm sure there's similar code with your interface. There were some things I liked about this pattern: * The code is simple. There's only one lock. The code doesn't have error conditions to test for, or exceptions being thrown, unless something else is broken. * There is one condition that must be checked, but even if you forgot to check it, it was probably just a missed optimization. You still had an exclusive lock at that point. * There was no such thing as a 'lock' object that wasn't actually locking a mutex. Interestingly: * This avoids a context switch over the "upgrade fails, calling code loops and tries again" methods. The thread asks for an upgrade and he doesn't resume execution until he has an exclusive. These days I probably wouldn't block forever on a single lock acquisition like that. I'm always waiting on at least two objects, one of them being a global event to signal application shutdown. - Marsh