[cpp-threads] Re: Thread API interface tweaks
Howard Hinnant
hinnant at twcny.rr.com
Wed Aug 30 18:31:06 BST 2006
On Aug 30, 2006, at 8:15 AM, Alexander Terekhov wrote:
>> void lock()
>> {
>> thread_id self = thread_id::current();
>> if (count_ > 0 && id_ == self)
>
> Um, you've got a data race here.
Hmm... If Alexander Terekhov tells me I've got a (detrimental) data
race, I'd be foolish not to take that to the bank. But I'm not
seeing it yet. However that's an aside (an implementation detail for
our purposes).
>> To implement this I needed the notion of
>> thread id.
>>
>
> Not really.
>
> key - tsd flag key
> lock - mutex (non-recursive lock)
> count - unsigned
Perhaps more correctly I should've said "wanted a thread id" instead
of needed one. I could be wrong, but at least on Mac OS the thread
specific data appears much more expensive than the thread id (and
associated test for equality). Your suggestion of tsd
(pthread_key_*, pthread_get/set_specific) and my suggestion of thread
id (pthread_t, pthread_equal) appear to serve exactly the same role
in this example. On the Mac, pthread_t is just a pointer (one word),
and its creation and destruction are already done by the thread. So
the only cost of the id is pointer assignment and comparison.
Admittedly I added one wrinkle that is not posix-standard to my
proposed thread_id that I should probably highlight (it was important
in my recursive_mutex adaptor):
A default constructed thread_id represents an id that is guaranteed
to not be equal to any valid thread id. I know this is easily
implemented on the Mac (just assign NULL to the pointer). I don't
know that for other OS's. But it appears (to me) to be an extremely
useful detail (and thanks go to Ion who rattled my cage on that
one). Indeed, if I remember correctly, I think I was looking at a
data race exactly where Alexander says I have one, and the "not a
thread id" solved it (as far as I can tell).
Anyway, bugs aside, I believe this still serves as a motivating use
case for the existence of a cheap-as-possible, equality-comparable
thread id.
-Howard
PS: In the interest of clarity, here's my entire recurisve_mutex,
slightly modified from what I had before, after looking at
Alexander's code (I believe checking count_ was harmless but
unnecessary):
template <class Mutex>
class recursive_mutex
{
private:
Mutex& mut_;
unsigned count_;
thread_id id_;
public:
explicit recursive_mutex(Mutex& mut)
: mut_(mut), count_(0) {} // id_ has "not a thread" value
void lock()
{
thread_id self = thread_id::current();
if (id_ == self)
++count_;
else
{
mut_.lock();
id_ = self;
store_release(&count_, 1);
}
}
void unlock()
{
if (--count_ == 0)
{
id_ = thread_id(); // id_ = "not a thread"
mut_.unlock();
}
}
};
Also for completeness, Ion has pointed out how variadic templates
would allow us to store a mutex, constructing it in place with
arbitrary, perfectly forwarded arguments, instead of referring to an
external mutex.
More information about the cpp-threads
mailing list