【问题标题】:Is there something wrong with this rwLock implementation?这个 rwLock 实现有问题吗?
【发布时间】:2023-03-17 13:30:02
【问题描述】:

我的程序死锁了,我不知道为什么,因为当我在调试器中运行它时它不会这样做,所以我的第一个怀疑是我的 rwLock,我编写了自己的版本,因为我只想使用标准库——我认为直到 C++17 才包含 rwLock——这不是我通常做的事情。

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();
}

【问题讨论】:

  • while(reading_threads) { condition.notify_all(); } 如果有读者,那将永远等待。您永远不会解锁锁,因此永远不会让读者有机会减少reading_threads。对我来说似乎是一个复制/粘贴错误 - 我敢打赌你的意思是condition.wait,而不是notify_all
  • @IgorTandetnik 我从另一个网站复制并修改了它,所以是的。我觉得线路是问题所在,但老实说,这两种情况对我来说都没有多大意义。
  • shared_timed_mutex 存在于 C++14 中

标签: c++ mutex rwlock


【解决方案1】:

std::shared_timed_mutex 存在于 C++17 之前:在 C++14 中。

改用它,它的错误更少,而且几乎可以肯定更快。

C++17 引入了shared_mutex,它可以更快。但我强烈怀疑您使用 C++ 标准原语实现比 shared_timed_mutex 更快的共享 rwlock 的能力。

【讨论】:

    【解决方案2】:

    看起来不错,除了这段代码中有两个问题:

    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();
    }
    

    首先,你增加writing_threads 太晚了。读者可能会偷偷溜进来。您可能不介意甚至不想要这个,但通常这是不希望的。

    其次,您在最后一个while 循环中的通知应该是wait。综上所述,我们得到:

    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();
    }
    

    这个其实简单一点,挺好的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 2011-09-28
      • 2011-12-14
      相关资源
      最近更新 更多