[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