
On Nov 15, 2007, at 7:37 AM, Phil Endecott wrote:
The semantics of pthread_mutex&cond_t are more complex than are needed for std::mutex&cond_var. Slightly more efficient pthread functions could be implemented by inlining (maybe some implementations already do this). But the overhead of using a single type for all kinds of mutex (recursive, non-recursive, checking etc), with run-time look up of the kind, is unavoidable. Since the optimal uncontended mutex locking code is just two inline instructions, even adding one additional 'if kind==x' will measurably reduce performance.
Your argument above addresses pthread_mutex_t but not pthread_cond_t. I too find it unfortunate that so much functionality got stuffed into pthread_mutex_t. And that is precisely why boost::mutex, and the proposed std::mutex separate out functionality into different types. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html#mutex_rat...
Like boost, and unlike POSIX, this design separates these functionalities into several distinct types which form a hierarchy of concepts. The rationale for the different types is to keep the most common, and simplest mutex type as small and efficient as possible. Each successive concept adds both functionality, and potentially expense.
That being said, the posix rationale includes the following statement on this issue:
Since most attributes only need to be checked when a thread is going to be blocked, the use of attributes does not slow the (common) mutex-locking case.
Apart from performance, another problem with wrapping existing functionality is that the lowest common denominator of all the constraints from the existing implementations has to be passed on to the user. For example, in the condition variable code that I posted, a mutex is locked from one thread and then unlocked from another. I think this works for all of the mutexes that I've written (spinlock, loop-calling-yield, futex) (though I may be missing something - I'm not an expert in any of this). Because it works with futex, I guess that the Linux pthread_mutex may also work in DEFAULT mode, though it's possible that there is something in glibc that breaks it. However, POSIX says that "if a thread attempts to unlock a mutex that it has not locked ... undefined behavior results." So the wording in N2447 also requires that "the current thread of execution shall own the mutex" before it can call unlock().
The Posix committee has considerable experience and expertise in this area. While I do not trust their advice blindly, I also do not dismiss it lightly (quite the contrary). Transferring mutex ownership among threads is not one of the decisions they have made that I've questioned. I've lacked the motivation. If you have strong motivation for relaxing this restriction, coupled with some insight into the posix decision and why it should be relaxed, I am most interested.
You are not the only one to have argued in this thread that the status-quo has been arrived at as a result of much deliberation by experts whose conclusions we should trust. While I don't exactly disagree with that attitude, I suggest that the level of deference might perhaps be dropped back one notch.
The rationale section in the pthread_mutex documentation says nothing about the restriction on locking in one thread and unlocking in another. Maybe some readers can propose an explanation? My guess is that someone, long ago, decided to prohibit behaviour that they couldn't think of a use for, and that this has simply been carried forward.
My motivation for relaxation is simply that it's useful (essential?) in the algorithm that I presented for a condition variable. (I'm curious to know if anyone has spotted any fundamental problems with that algorithm, by the way.)
David Butenhof (Programming with POSIX Threads) recommends semaphores for use cases where you want to lock in one thread and unlock in another. -Howard