Boost logo

Boost :

Subject: Re: [boost] [thread] upgrading read lock to write lock
From: Edd Dawson (lists_at_[hidden])
Date: 2011-02-07 15:36:50


On 2/7/2011 3:34 AM, Howard Hinnant wrote:
> On Feb 6, 2011, at 7:04 PM, Edd Dawson wrote:
>
>> What I'm trying to achieve is to be able to turn a read lock in to a write lock without forfeiting my 'turn'.
>> 1. Is this a realistic thing to expect to be able to achieve? I'm under the impression that this is the purpose of an upgradable locking facility. Perhaps this isn't the case, though?
>
> I'm not positive if upgradable locks fit your use case or not, mainly because I don't know enough about your use case. If *every* thread follows the algorithm you describe, then it probably won't work (except maybe as described below).

I had imagined that I might be able to write the code such that every thread
would be running the same code without any try-locking involved. I'm now seeing
that this goal is probably unrealistic.

> The way the upgrade_lock is meant to work is that a bunch of threads are able to obtain a shared_lock, and at the same time *one* thread obtains an upgrade_lock, which shares ownership with the other threads holding a shared_lock. Then if and when the thread with the upgrade_lock wants unique ownership, then he converts the upgrade_lock to a unique_lock. This operation blocks until all of the threads with the shared_locks give up their ownership. And then the conversion from upgrade to unique completes.

This is the root of my problem. It's not at all what I imagined upgrade_lock
would be for. Entirely my fault for making such a big and silly assumption. But
as a side comment, IMVHO the Boost.Threads documentation would benefit massively
from an analogue to your web page, or even some updated examples.

> A compromise solution (which boost doesn't support, but http://home.roadrunner.com/~hinnant/mutexes/locking.html does), is for a bunch of threads to hold shared_locks, and they can *all* /try/ to convert their shared_locks to either upgrade_locks or unique_locks. [...]
>
> Bringing this back to your problem, upgradeable locks will only work if there are some threads which need read access and don't ever want to upgrade to write access, or can at least choose to do something else if a try-conversion fails. A thread with an upgrade_lock can share threads holding shared_locks. But a thread with an upgrade_lock can not share with another thread needing an upgrade_lock.

Right. I think I'm just going to abandon this idea of holding on to my turn if I
need to write, now that I know the API wasn't designed for that in the first place!

So I sincerely hope I'm correct in saying that if each thread does the
following, I should be ok from a correctness point of view at the very least:

T &thread_local::data_for_current_thread()
{
     // scope for lock lifetime on shared_mutex, m.
     {
         shared_lock<shared_mutex> readlock(m);

         iterator f = tlcache.find(current_thread_id);
         if (f != tlcache.end()) return f->second;

         // else, we need to write
     }

     unique_lock<shared_mutex> writelock(m);
     return tlcache[current_thread_id] = T();
}

Thanks very much Howard for all the effort you've put in to providing sample
code and generally making all this clear to me!

Kind regards,

Edd


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk