在我的程序中,我有全局数据。
每个程序模块都必须具有对数据的读写权限。截至目前,我不使用线程,而是使用Qt的信号和插槽,因此 - 虽然我还没有遇到崩溃 - 但我认为我在某些时候需要同步。
因此,每个模块都保存这样的数据:
const std::vector<T>& data;
其中T是自定义类。因此,每个模块都可以读取数据。为了保持一致,vector
本身是const以禁止并发删除或删除。这些是使用可以同步的全局函数(如addToData(T elem)
,removeFromData(int id)
)完成的。请注意,向量本身声明为引用共享,因此上述某个全局函数的更改将导致每个程序模块中的数据一致。
==&GT;这意味着可以安全地从任何地方读取和添加/删除数据。
我遇到的问题是修改数据。 T
的制定者知道竞争条件。使用data
,我想允许调用data.at(3).setAttr("hello")
,但对于常量向量,at()只返回常量引用。为什么以及如何使其发挥作用?我可以抛弃常数,但这感觉不对。
考虑到我的架构,我也愿意接受建议。
答案 0 :(得分:2)
此场景正是您想要将constness转换为的地方。您已经仔细设计了系统以使其正常工作,因此当您完全准备好它并且正确时,不要感到严重关于丢弃const
要做。
答案 1 :(得分:2)
低开销解决方案(虽然没有很好地封装)如下所示。想法在@ JonathanWakely的评论中得到了很好的总结:“添加一个带有仿函数并将其应用于非const向量的全局函数”
header.h
struct no_synchronization {
struct mutex {}
struct guard {
guard(mutex&) {}
};
};
struct serialized {
typedef std::mutex mutex;
typedef std::lock_guard<mutex> guard;
};
template <class T, class S = no_synchronization>
class spaghetti {
typedef typename S::mutex mutex;
typedef typename S::guard guard;
static mutex mutex_;
static std::vector<T> vector_;
template <class F>
static void read_global_vec(F const& f) {
guard lock(mutex_);
std::vector<T> const& ref = vector_;
f(ref);
}
template <class F>
static void write_global_vec(F const& f) {
guard lock(mutex_);
f(vector_);
}
}
如果矢量的内容不经常变化,那么你可以使用copy_ on-write和shared_ptr将争用保持在最低限度。
答案 2 :(得分:2)
既然你提出了建议
vector
。这也可以摆脱你提到的全局功能,这很好。如果您希望班级的实例为const
,请在内部使用mutable
向量。const_cast
,但尝试将其隐藏在函数中的某个位置。 详细说明(1)因为我在评论中被要求:
您需要矢量功能,它非常适合您的需求。但是矢量的界面对于你需要的东西来说很笨拙。这是一种经常遇到的情况,包装器是默认解决方案。包装器是一个新类,具有符合您需求的接口,但它的实现几乎只是将所有工作委托给另一个类。使用包装器的目的是使包装器对象更容易使用,更难以使用错误。它可能看起来有点像(未经过测试,不会编译):
class AWrapperForDemonstration
{
public:
MyCustomClass& GetByIndex(int i) const // can throw
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage[i];
}
size_t Size(int i) const
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage.size();
}
void Add(MyCustomClass& addThis)
{
std::lock_guard<std::mutex> lock(_mutex);
_storage.push_back(addThis);
}
bool Remove(MyCustomClass& removeThis)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it =_storage.find(removeThis);
if (it == _storage.end())
return false;
_storage.erase(it);
}
template <F> void ForEach(F const& f) const
{
std::lock_guard<std::mutex> lock(_mutex);
for (auto& i : _storage)
f(i);
}
private:
std::vector<MyCustomClass> _storage;
std::mutex _mutex;
}