
Michael Glassford <glassfordm@hotmail.com> wrote: Peter Dimov wrote:
Michael Glassford wrote:
[...]
I'll think about your suggestion a bit more before I'll be able to comment, but just a quick note:
l = m.lock(); //Lock mutex m (first unlocking whatever mutex l was previously locking, if any)
This is not what will happen. m.lock() is executed first, then operator= is called and l is given the opportunity to release its lock. So if l happens to already hold m.lock(), the thread will deadlock. (And a deadlock can also occur if another thread holds a lock on m and is blocked on the mutex currently locked by l.)
Actually, the comment in my pseudo-code above is an oversimplification of what I was actually thinking would happen. The actual transfer mechanism (when transfering from a mutex, at least) would be that the mutex would not actually be locked until the information was extracted from the lock_transfer object; the steps would be:
1) The mutex would build a lock_transfer object containing enough information to lock the mutex (this could be as simple as a this pointer and a member function pointer, either "raw" or using boost::bind or boost::function). 2) The lock_transfer object would be passed to the lock object's construtor or operator=. 3) The lock object would unlock itself if it's locked. 4) The lock object would extract the information from the lock_transfer object, which would lock the mutex in the process.
This would also have the advantage that, if the information is never extracted from the lock_transfer object (for example, if mutex.lock() were called but the result were not assigned to a lock object), the mutex would never be locked.
What is happenning on concurrent m.lock() invocations with the lock transfer object and their subsequent simultaneous use? Matt.