0
\$\begingroup\$

I've built a read/write lock and have been testing it without encountering any problems. It was made to avoid writer starvation, but I believe it works against reader starvation as well. I've seen alternatives online, but was wondering if this is a solid implementation.

If you use a normal shared mutex, new read actions can still be queued, which will prevent write actions from ever being processed while there is any read action present. This will cause starvation. I used a second mutex which will be locked by the write process and prevents any new read processes to be queued. Thank you!

class unique_priority_mutex
{
public:

    void lock_shared(void)
    {
        // If there is a unique operation running, wait for it to finish.
        if( this->_is_blocked ){
            // Use a shared lock to let all shared actions through as soon as the unique action finishes.
            std::shared_lock<std::shared_mutex> l(this->_unique_mutex);
        }

        // Allow for multiple shared actions, but no unique actions.
        this->_shared_mutex.lock_shared();
    }

    void unlock_shared(void)
    {
        this->_shared_mutex.unlock_shared();
    }

    void lock(void)
    {
        // Avoid other unique actions and avoid new shared actions from being queued.
        this->_unique_mutex.lock();

        // Redirect shared actions to the unique lock.
        this->_is_blocked = true;

        // Perform the unique lock.
        this->_shared_mutex.lock();
    }

    void unlock(void)
    {
        this->_shared_mutex.unlock();
        this->_is_blocked = false;
        this->_unique_mutex.unlock();
    }

    std::shared_mutex _shared_mutex;
    std::shared_mutex _unique_mutex;
    std::atomic<bool> _is_blocked = false;
};
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You'd need _shared_mutex and _is_blocked to flip together 'atomically' in order for this code to work, no?

Imaging one thread in lock() just flipped _unique_mutex and before it flips _is_blocked, another thread in lock_shared() is testing _is_blocked.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for your answer. The worst thing that can happen is that in between these actions which should happen simultaneously, a few read actions can overtake the write action ... no deadlocks or (writer) starvation, right? \$\endgroup\$
    – JMRC
    Feb 17, 2021 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.