Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Okay, I solved it.</p> <p>It can be done with just 2 semaphores, a critical section and almost no more locking than for a regular non-recursive MRSW lock (there is obviously some more CPU-time spent inside the lock because that multimap must be managed) - but it's <b>tricky</b>. The structure I came up with looks like this:</p> <p><pre><code> // Protects everything that follows, except mWriterThreadId and mRecursiveUpgrade CRITICAL_SECTION mLock; // Semaphore to wait on for a read lock HANDLE mSemaReader; // Semaphore to wait on for a write lock HANDLE mSemaWriter; // Number of threads waiting for a write lock. int mWriterWaiting; // Number of times the writer entered the write lock. int mWriterActive; // Number of threads inside a read lock. Note that this does not include // recursive read locks. int mReaderActiveThreads; // Whether or not the current writer obtained the lock by a recursive // upgrade. Note that this member might be set outside the critical // section, so it should only be read from by the writer during his // unlock. bool mRecursiveUpgrade; // This member contains the current thread id once for each // (recursive) read lock held by the current thread in addition to an // undefined number of other thread ids which may or may not hold a // read lock, even inside the critical section (!). std::multiset&lt;unsigned long&gt; mReaderActive; // If there is no writer this member contains 0. // If the current thread is the writer this member contains his // thread-id. // Otherwise it can contain either of them, even inside the // critical section (!). // Also note that it might be set outside the critical section. unsigned long mWriterThreadId; </pre></code></p> <p>Now, the basic idea is this:</p> <p>Full update of <code>mWriterWaiting</code> and <code>mWriterActive</code> for an unlock is performed by the unlocking thread. </p> <p>For <code>mWriterThreadId</code> and <code>mReaderActive</code> this is not possible, as the waiting thread needs to insert itself when it was released.</p> <p>So the rule is, that you may never access those two members <b>except</b> to check whether you are holding a read lock or are the current writer - specifically it may not be used to checker whether or not there are <b>any</b> readers / writers - for that you have to use the (somewhat redundant but necessary for this reason) <code>mReaderActiveThreads</code> and <code>mWriterActive</code>.</p> <p>I'm currently running some test code (which has been going on deadlock- and crash-free for 30 minutes or so) - when I'm sure that it's stable and I've cleaned up the code somewhat I'll put it on some pastebin and add a link in a comment here (just in case someone else ever needs this).</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload