全局状态
1) 这是一个好的做法吗?也就是说,使用“全局”Gamestate类是一个好主意吗?有没有更好的方法?
对于游戏而言,相较于一些可重用的代码,我认为全局状态已经足够了。你甚至可以避免在程序中传递gamestate指针,将其变成全局变量。
同步
2) 我的意图是在getters/setters中为Gamestate添加互斥锁,但这对于读取操作来说并不起作用,因为我不能在对象仍处于锁定状态时返回它,这意味着我必须在getters/setters之外进行同步,并使互斥锁公开化。这也意味着我需要为所有不同的资源拥有大量的互斥锁。有什么更优雅的方法来解决这个问题?
我会尝试以事务的方式思考这个问题。将每个状态更改都包装在自己的互斥锁代码中不仅会影响性能,而且如果代码获取一个状态元素,在之后执行一些计算并设置值,而其他代码在其中修改了相同的元素,则可能导致实际上的错误行为。因此,我会尝试以这样的方式构建
LogicManager
和
Renderer
,使得所有与Gamestate的交互都捆绑在几个地方。在该交互期间,线程应持有状态的互斥锁。
如果您想强制使用互斥锁,那么可以创建一些构造,其中至少有两个类。我们称它们为
GameStateData
和
GameStateAccess
。
GameStateData
将包含所有状态,但不提供对其的公共访问。
GameStateAccess
将是
GameStateData
的友元,并提供对其私有数据的访问。
GameStateAccess
的构造函数将采用对
GameStateData
的引用或指针,并锁定该数据的互斥锁。 析构函数将释放互斥锁。 这样,您操作状态的代码将简单地编写为一个作用域内存在
GameStateAccess
对象的块。
然而,仍然存在漏洞:在从此
GameStateAccess
类返回的对象是指向可变对象的指针或引用的情况下,这种设置无法阻止您的代码将这样的指针带出受互斥锁保护的范围。 为了防止这种情况,请注意如何编写代码,或者使用一些自定义指针类模板,一旦
GameStateAccess
超出范围就可以清除它,或者确保只通过值而不是引用传递东西。
例子
使用C++11,锁管理的上述想法可以实现如下:
class GameStateData {
private:
std::mutex _mtx;
int _val;
friend class GameStateAccess;
};
GameStateData global_state;
class GameStateAccess {
private:
GameStateData& _data;
std::lock_guard<std::mutex> _lock;
public:
GameStateAccess(GameStateData& data)
: _data(data), _lock(data._mtx) {}
int getValue() const { return _data._val; }
void setValue(int val) { _data._val = val; }
};
void LogicManager::performStateUpdate {
int valueIncrement = computeValueIncrement();
{ GameStateAccess gs(global_state);
int oldValue = gs.getValue();
int newValue = oldValue + valueIncrement;
gs.setValue(newValue);
}
cleanup();
}
循环终止指示器
3) I have all of the threads accessing "bool run" to check if to continue their loops
while(gs->run){
....
}
run gets set to false if I receive a quit message in the EventManager. Do I need to synchronize that variable at all? Would I set it to volatile?
对于这个应用程序,一个易失但不同步的变量应该是可以的。你必须声明它易失以防止编译器生成缓存该值的代码,从而隐藏另一个线程的修改。
作为替代方案,您可能想要使用
std::atomic
变量。
指针间接引用开销
这取决于其他选择。在许多情况下,如果以上代码中的
gs->objects->entitylist.at(2)
被重复使用,编译器将能够保持其值,并且不必一遍又一遍地计算它。一般来说,我认为由于所有这些指针间接引用而导致的性能损失是次要的问题,但这很难确定。