4

I am in search of an upgradeable read write lock for win32 with the behaviour of pthreads rwlock, where a read lock can be up- and downgraded.

What I want:

pthread_rwlock_rdlock( &lock );
...read...
if( some condition ) {
    pthread_rwlock_wrlock( &lock );
    ...write...
    pthread_rwlock_unlock( &lock );
}
...read...
pthread_rwlock_unlock( &lock );

The upgrade behaviour is not required by posix, but it works on linux on mac.

Currently, I have a working implementation (based on an event, a semaphore and a critical section) that is upgradeable, but the upgrade may fail when readers are active. If it fails a read unlock + recheck + write lock is necessary.

What I have:

lock.rdlock();
...read...
if( some condition ) {
    if( lock.tryupgrade() ) {
        ...write...
        lock.unlock();
        return;
    } else {
        lock.unlock();
        // <- here, other threads may alter the condition ->
        lock.wrlock();
        if( some condition ) { // so, re-check required
            ...write...
        }
        lock.unlock();
        return;
    }
}
...read...
lock.unlock();

EDIT: The bounty:

I am still in search, but want to add some restrictions: it is used intra-process-only (so based on critical sections is ok, WIN32 mutexes are not ok), and it should be pure WIN32 API (no MFC, ATL etc.). Acquiring read locks should be fast (so, acquiring the read lock should not enter a critical section in its fast path). Maybe an InterlockedIncrement based solution is possible?

Frunsi
  • 7,099
  • 5
  • 36
  • 42

3 Answers3

1

The boost shared_mutex class supports reader (shared) and writer (unique) locks and temporary upgrades from shared to unique locks.

Example for boost shared_mutex (multiple reads/one write)?

I don't recommend writing your own, it's a tricky thing to get right and difficult to test thoroughly.

Community
  • 1
  • 1
Tim Sylvester
  • 22,897
  • 2
  • 80
  • 94
  • The win32 implementation of `boost::shared_mutex` looks promising. The pthread implementation is not so pretty (it has more than I need, and so the method they use maybe is not as efficient as pthread_rwlock_ with the non-standard upgrade behaviour..). I'll give it a try... – Frunsi Dec 15 '09 at 22:18
  • Well, its perfect, and after reading the documentation and trying it out, it all makes sense now :-) – Frunsi Dec 16 '09 at 03:46
0

pthread library is a 'Portable Threads' library. That means it's also supported on windows ;) Have a look: Pthreads-w32.

Additionally, consider using OpenMP instead of locks: the compiler extension provides portable critical sections, kernes threading model, tasks and much more! MS C++ supports this technology as well as g++ in Linux.

Cheers! :)

kolypto
  • 31,774
  • 17
  • 105
  • 99
0

What is wrong with this approach?

    // suppose:
    struct RwLock
    {
        void AcquireExclusive();
        void AcquireShared();
        void Release();
        bool TryAcquireExclusive();
    };

    // rwlock that has TryAcquireSharedToExclusive
    struct ConvertableRwLock
    {
        void AcquireExclusive()
        {
            writeIntent.AcquireExclusive();
            rwlock.AcquireExclusive();
            writeIntent.Release();
        }

        void AcquireShared()
        { 
            readIntent.AcquireShared();
            rwlock.AcquireShared();
            readIntent.Release();
        }

        void Release()
        {
            rwlock.Release();
        }

        bool TryConvertSharedToExclusive()
        {
            // Defer to other exclusive including convert.
            // Avoids deadlock with other TryConvertSharedToExclusive.
            if (!writeIntent.TryAcquireExclusive())
            {
                rwlock.Release();
                return false;
            }

            // starve readers
            readIntent.AcquireExclusive();

            // release full lock, but no other can acquire since
            // this thread has readIntent and writeIntent.
            rwlock.Release();

            // Wait for other shared to drain.
            rwlock.AcquireExclusive();

            readIntent.Release();
            writeIntent.Release();
            return true;
        }

    private:
        RwLock rwlock;
        RwLock readIntent;
        RwLock writeIntent;
    };
Jay K
  • 129
  • 3