来自多个线程的共享锁可能会使寻找独占锁的单个线程饿死

Shared locks from multiple threads can starve a single thread looking for an exclusive lock

假设我有几个线程从共享内存中读取数据。所有这些线程都重复获取共享互斥体上的共享锁以访问此内存。

假设我有一个写入此共享内存的线程,它获取了独占锁。

如果有足够多的读线程,可能永远不会有一个写线程能够获取独占锁的时间点,因为共享锁在任何时间点都被多个线程持续持有。

解决这个问题最简单直接的模式是什么?我正在寻找一种简单直接的方法来解决这个问题,最好是使用 STL。

C++ 中的示例实现也会有所帮助。

我的首选方案是CsLibGuarded,您可以选择费用。

我已经使用了lr_guarded,这样写入修改一个副本,而读取在另一侧继续,然后当写入完成时,所有新的读取都会转到修改后的一侧,依此类推。在所有读者离开后,写入也可以修改另一侧。

(未经测试的代码)

using MapType = std::map<std::string, std::shared_ptr<ComplicatedObject>>;
lr_guarded<MapType> map;

void MyCache::insert(std::string key, std::shared_ptr<ComplicatedObject> element) {
 m_cache.modify(
 [&key, &element]
 (MapType & map) {
 map.emplace(key, element);
 });
}

这应该有效。

它并不复杂,如果您有多个作者,则不提供任何订单保证。但它应该有效。

#include <condition_variable>
#include <mutex>

class RWLock
{
    std::mutex                  lock;
    std::condition_variable     writeWaiters;
    std::condition_variable     readWaiters;

    int                         waitingWriters;
    int                         currentWriters;
    int                         currentReaders;

    public:
        RWLock()
            : waitingWriters(0)
            , currentWriters(0)
            , currentReaders(0)
        {}

    private:
        friend class RGuard;
        void readLock()
        {
            std::unique_lock<std::mutex>     guard(lock);
            readWaiters.wait(guard, [&]{return waitingWriters == 0;});
            ++currentReaders;
        }
        void readUnLock()
        {
            std::unique_lock<std::mutex>     guard(lock);
            --currentReaders;
            if (currentReaders == 0) {
                writeWaiters.notify_one();
            }
        }
    private:
        friend class WGuard;
        void writeLock()
        {
            std::unique_lock<std::mutex>     guard(lock);
            ++waitingWriters;

            writeWaiters.wait(guard, [&]{return (currentReaders != 0 || currentWriters != 0);});
            ++currentWriters;
        }
        void writeUnLock()
        {
            std::unique_lock<std::mutex>     guard(lock);
            --waitingWriters;
            --currentWriters;
            if (waitingWriters != 0) {
                writeWaiters.notify_one();
            }
            else {
                readWaiters.notify_all();
            }
        }
}
class RGuard
{
    RWLock&     lock;
    public:
        RGuard(RWLock& lock)
            : lock(lock)
        {
            lock.readLock();
        }
        ~RGuard()
        {
            lock.readUnLock();
        }
};
class WGuard
{
    RWLock&     lock;
    public:
        WGuard(RWLock& lock)
            : lock(lock)
        {
            lock.writeLock();
        }
        ~WGuard()
        {
            lock.writeUnLock();
        }
};

int main()
{
    RWLock  lock;
    RGuard  guardR(lock);
    WGuard  guardW(lock);
}