c++ - protected 数据设计模式

标签 c++ design-patterns concurrency mutex guard

在我们的应用程序中,我们处理在工作线程中处理并在显示线程中访问的数据,并且我们有一个负责关键部分的互斥锁。没什么特别的。

现在我们考虑重新编写我们的代码,其中当前锁定是由持有和处理数据的一方明确完成的。我们想到了一个单一的实体来保存数据,并且只允许以 protected 方式访问数据。

为此,我们有一个名为 GuardedData 的类。调用者可以请求这样的对象,并且应该只在本地范围内将其保留很短的时间。只要对象还活着,它就会保持锁定状态。一旦对象被销毁,锁就会被释放。数据访问与锁定机制相结合,调用者无需任何明确的额外工作。类(class)的名字让调用者想起了现在的守卫。

template<typename T, typename Lockable>
class GuardedData {
    GuardedData(T &d, Lockable &m) : data(d), guard(m) {}
    boost::lock_guard<Lockable> guard;
    T &data;

    T &operator->() { return data; }
};

同样,一个非常简单的概念。 operator-> 模仿 STL 迭代器的语义来访问有效载荷。

现在我想知道:

  • 这种方法是否广为人知?
  • 是否有像这样的模板类已经可用,例如在 boost 库中?

我问是因为我认为这是一个相当通用且可用的概念。不过我找不到类似的东西。

最佳答案

根据它的使用方式,您几乎可以肯定会在某个时候遇到死锁。如果你想对 2 条数据进行操作,那么你最终会锁定互斥量两次并发生死锁(除非每条数据都有自己的互斥量 - 如果锁定顺序不一致,这也会导致死锁 - 你无法控制有了这个方案就不会让它变得非常复杂)。除非您使用可能不需要的递归互斥体。

此外,您的 GuardedData 对象是如何传递的? boost::lock_guard 是不可复制的——它引发了互斥量的所有权问题,即它何时何地被释放。

在需要时将您需要的部分数据复制到读取器/写入器线程可能更容易,同时保持关键部分简短。作者同样会一次性提交数据模型。

本质上,您的查看器线程在给定时间获取所需数据的快照。这甚至可能完全适合位于运行线程的核心附近的 cpu 缓存,并且永远不会进入 RAM。编写器线程可能会在读取器处理它时修改基础数据(但这应该使 View 无效)。然而,由于查看器有一个拷贝,它可以继续并提供与数据同步时的数据 View 。

另一种选择是为 View 提供指向数据的智能指针(应将其视为不可变的)。如果编写器希望修改数据,它会在此时复制数据,修改拷贝,完成后,将指针切换到模型中的数据。这将需要在处理时阻止所有读者/作者,除非只有 1 位作者。下次读取器请求数据时,它会得到新的拷贝。

关于c++ - protected 数据设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15548840/

相关文章:

algorithm - 学习编程技巧的优先顺序及其他建议

design-patterns - 在域对象方法中封装服务调用

Java - 多个并发 runtime.exec() InputStreams 的问题

java - 为什么我们不应该吞下 InterruptedException

java - final 变量和 lazySet 实现都需要 LoadStore 和 StoreStore 吗?

c++ - 根据模板参数的模板函数名称

c++ - 在 XCode 中快速创建和运行新的 C++ 文件

c++ - 复制列表初始化是否在概念上调用复制构造函数?

c++ - 在条件中更改对象类型

android - Android 开发的架构模式