简体   繁体   中英

Is there something wrong with this rwLock implementation?

My program is deadlocking, and I have no idea why, given that it won't do it when I run it in a debugger, so my first suspect is my rwLock, I wrote my own version because I only wanted to use standard libraries--I don't think a rwLock is included until C++17--and this isn't the sort of thing I normally do.

class RwLock
{
    std::mutex mutex;
    std::unique_lock<std::mutex> unique_lock;
    std::condition_variable condition;

    int  reading_threads;
    bool writing_threads;

public:
    RwLock();
    ~RwLock();

    void read_lock();
    void read_unlock();

    void write_lock();
    void write_unlock();
};


RwLock::RwLock() :
    mutex(),
    unique_lock(mutex, std::defer_lock),
    condition(),
    reading_threads(0),
    writing_threads(false)
{
}

RwLock::~RwLock()
{
    //TODO: find something smarter to do here.
    write_lock();
}

void RwLock::read_lock()
{
    unique_lock.lock();

    while(writing_threads)
    {
        condition.wait(unique_lock);
    }

    ++reading_threads;
    unique_lock.unlock();
}

void RwLock::read_unlock()
{
    unique_lock.lock();

    if(--reading_threads == 0)
    {
        condition.notify_all();
    }

    unique_lock.unlock();
}

void RwLock::write_lock()
{
    unique_lock.lock();

    while(writing_threads)
    {
        condition.wait(unique_lock);
    }

    writing_threads = 1;

    while(reading_threads)
    {
        condition.notify_all();
    }

    unique_lock.unlock();
}

void RwLock::write_unlock()
{
    unique_lock.lock();
    writing_threads = 0;
    condition.notify_all();
    unique_lock.unlock();
}

std::shared_timed_mutex exists prior to C++17: in C++14.

Use it instead, it will have fewer bugs and be faster almost certainly.

C++17 introduces shared_mutex which can be even faster. But I strongly doubt your ability to implement a faster shared rwlock than shared_timed_mutex using C++ standard primitives.

Looks good except for two issues in this code:

void RwLock::write_lock()
{
    unique_lock.lock();

    while(writing_threads)
    {
        condition.wait(unique_lock);
    }

    writing_threads = 1;

    while(reading_threads)
    {
        condition.notify_all();
    }

    unique_lock.unlock();
}

First, you increment writing_threads too late. A reader could sneak in. It's possible that you don't mind or even want this, but typically this is undesired.

Second, your notify in the last while loop should be a wait . Putting it together, we get:

void RwLock::write_lock()
{
    unique_lock.lock();

    ++writing_threads;

    while((writing_threads > 1) || (reading_threads > 0))
    {
        condition.wait(unique_lock);
    }

    unique_lock.unlock();
}

void RwLock::write_unlock()
{
    unique_lock.lock();
    --writing_threads; // note change here
    condition.notify_all();
    unique_lock.unlock();
}

This is actually a bit simpler, which is nice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM