在我们的应用程序中,我们处理在工作线程中处理并在显示线程中访问的数据,并且我们有一个负责关键部分的互斥锁。没什么特别的。
现在我们考虑重新编写我们的代码,其中当前锁定是由持有和处理数据的一方明确完成的。我们想到了一个单一的实体来保存数据,并且只允许以 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/