多个线程可以具有只读访问权限的互斥模式

Posted

技术标签:

【中文标题】多个线程可以具有只读访问权限的互斥模式【英文标题】:Mutex pattern where multiple threads can have read-only access 【发布时间】:2015-07-06 09:13:36 【问题描述】:

我有一个Dinosaur 对象列表,可以添加、删除这些对象,恐龙本身需要喂食。这一切都发生在高度多线程的环境中,因此列表受互斥体保护。

static Mutex s_dinosaurMutex;
static vector<Dinosaur> s_dinosaurList;

void AddDinosaur(const Dinosaur& dinosaur)

    s_dinosaurMutex.Lock();
    s_dinosaurList.push_back(dinosaur);
    s_dinosaurMutex.Unlock();


void RemoveDinosaur(const Dinosaur& dinosaur)

    s_dinosaurMutex.Lock();

    vector<IMadderReceiver*>::iterator it = find(s_dinosaurList.begin(), s_dinosaurList.end(), dinosaur);
    if (it != s_dinosaurList.end())
        s_dinosaurList.erase(it);

    s_dinosaurMutex.Unlock();


void FeedDinosaur(const Dinosaur& dinosaur)

    s_dinosaurMutex.Lock();

    vector<IMadderReceiver*>::iterator it = find(s_dinosaurList.begin(), s_dinosaurList.end(), dinosaur);
    if (it != s_dinosaurList.end())
        (*it).Feed(); // Feeding a dinosaur can take a long time, ~ 1 second

    s_dinosaurMutex.Unlock();

现在问题出在喂食上。这可能需要很长时间,但如果多个线程同时喂食相同(或不同)的恐龙,那绝对没问题。因此,馈送过程不应停止其他 FeedDinosaur 调用,尽管它应该为 Add 和 Remove 调用停止,并等待这些调用完成。目前的行为是许多线程正在排队等待喂食恐龙,这使得系统陷入僵局。

是否有一种特殊的(类似互斥的)设计模式允许这种需要只读访问的正常线程的行为?

【问题讨论】:

是的,这就是“读写锁”的用途。 除了@Sneftel 提到的之外,我还建议在您的互斥体周围使用 RAII 包装器,例如 std::lock_guard,以确保在函数的每个退出路径上释放互斥体 Reader/Writer Locks in C++ 的可能重复项 【参考方案1】:

这是一个读写器互斥锁; Boost 和 C++ 使用更通用的术语“共享互斥锁”,因为它可以用于多读单写以外的模式。

Boost.Thread 从版本 1.35.0 (Reader/Writer Locks in C++) 开始就有 shared_mutex。 C++ 自 C++14 起具有 shared_timed_mutex,在 C++17 中将具有 shared_mutex;在可用之前,您可以使用 C++14 shared_timed_mutex 而只是不使用超时机制。

在您的编写线程中,锁定共享互斥体以进行唯一 访问(使用unique_lock);在您的阅读器线程中,锁定共享互斥锁以进行 shared 访问(使用 shared_lock)。

【讨论】:

很好的答案,谢谢。除了使用 Boost 之外,是否有 C++11 替代方案? @Yellow 很难正确有效地实施 - 请参阅 ***.com/questions/12033188/…

以上是关于多个线程可以具有只读访问权限的互斥模式的主要内容,如果未能解决你的问题,请参考以下文章

是否可以创建具有只读访问权限的死锁?

如何授予 Redshift 中所有模式的使用权限?

同时从多个线程访问只读数据是不是明智?

具有只读访问权限的 Sql 虚拟表:插入、删除、更新?

分布式锁总结

分布式锁总结