我正在为一个多线程俄罗斯方块游戏实现类似观察者设计模式的机制。有一个Game类,其中包含一组EventHandler对象。如果一个类想要将自己注册为Game对象的监听器,则必须继承Game::EventHandler类。在状态改变事件中,每个监听器的EventHandler接口都会调用相应的方法。下面是代码示例:
class Game
{
public:
class EventHandler
{
public:
EventHandler();
virtual ~EventHandler();
virtual void onGameStateChanged(Game * inGame) = 0;
virtual void onLinesCleared(Game * inGame, int inLineCount) = 0;
private:
EventHandler(const EventHandler&);
EventHandler& operator=(const EventHandler&);
};
static void RegisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler);
static void UnregisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler);
typedef std::set<EventHandler*> EventHandlers;
EventHandlers mEventHandlers;
private:
typedef std::set<Game*> Instances;
static Instances sInstances;
};
void Game::RegisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler)
{
ScopedReaderAndWriter<Game> rwgame(inGame);
Game * game(rwgame.get());
if (sInstances.find(game) == sInstances.end())
{
LogWarning("Game::RegisterEventHandler: This game object does not exist!");
return;
}
game->mEventHandlers.insert(inEventHandler);
}
void Game::UnregisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler)
{
ScopedReaderAndWriter<Game> rwgame(inGame);
Game * game(rwgame.get());
if (sInstances.find(game) == sInstances.end())
{
LogWarning("Game::UnregisterEventHandler: The game object no longer exists!");
return;
}
game->mEventHandlers.erase(inEventHandler);
}
我经常遇到这种模式的两个问题:
- 监听器对象希望在已经删除的对象上取消注册,结果导致崩溃。
- 事件被发送到不再存在的监听器。这在多线程代码中最常见。以下是一个典型的场景:
- 游戏状态在工作线程中发生变化。我们希望通知发生在主线程中。
- 该事件被包装在boost::function中,并作为PostMessage发送到主线程。
- 短时间后,当Game对象已经被删除时,该函数对象被主线程处理。结果是崩溃。
有人知道如何干净而安全地实现通知器/监听器系统的一组准则吗?有什么建议可以避免上述问题吗?
PS:如果您需要更多信息来回答这个问题,您可以在此处在线找到相关代码:Game.h,Game.cpp,SimpleGame.h,SimpleGame.cpp,MainWindow.cpp。
shared_ptr<T>
和weak_ptr<T>
。 - fredoverflow