[cpp-threads] N2800's C/C++MM and read-write locking
Alexander Terekhov
alexander.terekhov at gmail.com
Thu Jan 8 18:42:43 GMT 2009
On Thu, Jan 8, 2009 at 5:50 PM, Paul E. McKenney
<paulmck at linux.vnet.ibm.com> wrote:
> On Thu, Jan 08, 2009 at 04:01:28PM +0200, Peter Dimov wrote:
>> >> I also often tend to think of "rwlocks" as shared/exclusive locks. If
>> >> you really
>> >> want to use weaker fences for readers, I think you would need to split
>> >> them
>> >> into two variantes: shared/exclusive and read/write.
>> >
>> > Care to elaborate?
>>
>> Something like:
>>
>> take shared lock
>> try STM transaction in a lock-free manner
>> unlock
>>
>> if failed
>> take write lock
>> use ordinary ops
>> unlock
>>
>> Here the lock is not used as a pure read lock since the transaction contains
>> writes.
>
> I agree with Peter. In fact, I have come across situations where one
> read-acquires the lock to protect an update and write-acquires the lock
> to protect a read. What, you don't believe me? ;-) Read on, then...
>
> Here is such an example, which assumes per-thread variables that I
> represent as arrays, as I cannot remember what if anything C++0x does
> with thread-local storage. I also invent a me() function that returns
> a small integer uniquely identifying the current thread, and I steal
> the Linux-kernel syntax for reader-writer locks.
>
> Yes, this sort of thing really has been used in production in real life.
> Explanation after example.
>
> long count[N_THREADS] = 0;
> DEFINE_RWLOCK(rwl);
>
> void get_reference(void)
> {
> read_lock(&rwl);
> count[me()]++;
> read_unlock(&rwl);
> }
>
> void put_reference(void)
> {
> read_lock(&rwl);
> count[me()]--;
> read_unlock(&rwl);
> }
>
> /*
> * Caller must write-hold rwl.
> */
> int no_references(void)
> {
> int i;
>
> for (i = 0; i < N_THREADS; i++)
> if (count[i] != 0)
> return 0;
> return 1;
> }
>
> /* Sample use. */
>
> write_lock(&rwl);
> if (no_references())
> perform_action_requiring_there_be_no_references();
> write_unlock(&rwl);
>
What's the problem with insisting to add extra fencing to
get_reference() and put_reference() in the case of using rwl in
(shared-)read(-only) mode?
With full set of locking modes
shared-read-only
shared-write-only
shared-read-write
exclusive-read-only
exclusive-write-only
exclusive-read-write
your example would be
long count[N_THREADS] = 0;
DEFINE_RWLOCK(rwl);
void get_reference(void)
{
long r = count[me()];
shared_write_only_lock(&rwl);
count[me()] = r + 1; // or simply
++count[me()] without r
shared_write_only_unlock(&rwl);
}
void put_reference(void)
{
long r = count[me()];
shared_write_only_lock(&rwl);
count[me()] = r - 1; // or simply
--count[me()] without r
shared_write_only_unlock(&rwl);
}
/*
* Caller must hold exclusive-read-only lock on rwl
*/
int no_references(void)
{
int i;
for (i = 0; i < N_THREADS; i++)
if (count[i] != 0)
return 0;
return 1;
}
/* Sample use. */
exclusive_read_only_lock(&rwl);
if (no_references())
perform_action_requiring_there_be_no_references();
exclusive_read_only_unlock(&rwl);
correct?
And Peter's example:
take shared-read-write lock
try STM transaction in a lock-free manner
release shared-read-write lock
if failed
take exclusive-read-write lock
use ordinary ops
release exclusive-read-write lock
right?
regards,
alexander.
More information about the cpp-threads
mailing list