I am trying to build a sender-receiver model in C++. I want to send data from sender to receiver in the feed-forward way. Shortly, the desired architecture could be expressed like so (elementary units are called nodes):
Each node can receive (send) data from (to) another node. Each node has as many as desired senders (receivers). Each node has a number called impulse which is data supposed to be sent. Let's call one data propagation through a whole network a cycle. Then in one cycle each node that belongs to the network must send impulse once and only once to all its receivers.
A scratch of the implementation of the above idea is the following.
class Node
{
private :
double in_signal;//received data
double out_signal;//data to send
bool is_opened;//status of channel
void update_in( double package );//receive new package
protected :
std::vector<Node*> receivers;
public :
Node( double out_signal )
: in_signal(0.),
out_signal(out_signal),
is_opened(false)
{}
~Node() {}
void add_receiver( Node* receiver );
void emit();//send out_signal or impulse
};
void Node::update_in( double package )
{
//the problem is how to control the status of the channel:
//it must be closed after getting all data
if ( not is_opened )
{
in_signal = 0.;//reset
is_opened = true;
}
in_signal += package;
}
void Node::add_receiver( Node* receiver )
{
receivers.push_back( receiver );
}
void Node::emit()
{
for ( auto& receiver : receivers )
{
receiver->update_in( out_signal );
}
}
The problem I cannot solve is multi-threading behind this architecture:
The node's in_signal can be updated by several senders, but senders work independently (required) therefore I am afraid of arising concurrency.
So I am asking about
How to solve this multi-thereading problem?
How to decide if all data has been received?
I will be thankful for some ideas, patterns, conceptions etc.
First of all, IMHO, this is an oversimplification about your problem.
I think, for example, your data couldn't be simply double.
Anyway:
If in your architecture you have a race condition (if each node has it's own thread, you clearly have a race condition), i don't see any solution but mutex.
It depens on real task vastity and complexity, but you could apply some rule to let nodes be capable of understand lifetime of packets (some ideas: sequence number for packets, list of near nodes, etc.).
To protect a variable I recommend you use a test-and-set method, which is a simple mechanism for synchronizing access to a variable that is shared by multiple threads.
In Windows the most common way to do that is by using the InterlockedExchange function.
For linux just use this wrapper [1]:
template<typename T> T InterlockedExchange(T& data, T& new_val)
{
return __sync_lock_test_and_set(&data, new_val);
}
Related
In my current application I am receiving spectral data through a spectrometer. This data is accumulated for one second and then put into a circular buffer. For now I have one consumer, who pops entries from the buffer and then saves everything to disk. Ok all of that stuff works. Now what I need to do is add another consumer, who, in parallel to the saving, does some processing with the spectra. So I have two consumers needing the exact same data (note: they only read and don't modify). Ok but this doesn't work because if one of the consumers pops one entry of the buffer it is gone, so the other would not receive it. I guess the simplest solution to this problem is to give every consumer it's own circular buffer. Fine, but the only problem is: the data entries are big. One entry has a maximum size of around 80MB, so in order to save memory it would be great to not have the same data there twice. Is there any better solution?
Note: I am using a circular buffer so it is ensured that the buffer has a growing limit.
Keep two different tail pointers in your buffer, one for each consumer. When the producer is updating the queue, use the farthest tail pointer (the tail pointer which is lagging behind) to check if the buffer is full. Consumers can use their own tail pointers to check if the buffer is empty. This way we get a lockfree buffer, and there is no copying around of data.
See the implementation of disruptor exchange for a discussion about the performance improvement with this solution.
I should hope you're receiving your data directly into the queue and not copying it around much....
Any valid solution that would keep a single copy of the data would have to sync all the consumers so that only when they're all done with an entry it can be popped.
You can keep your circular buffer. You only need a single remover to remove an entry when the readers are done with it. I strongly suggest this remover to be the writer of the data. This way it'd be the only guy with write access to the queue, and that simplifies things.
The remover can be fed from the consumers telling it what are they done with.
Consumers can share their read offsets with the remover. You can use atomic_store on the consumer side, and atomic_load on the remover side.
It should be something like that:
struct Consumer {
...
long offset = 0;
...
Consumer() {
q.remover->add(this);
}
...
void run() {
for(;;) {
entry& e = q.read( offset );
process( e );
atomic_store( &offest, offset + e.size() );
}
}
};
struct Remover {
...
long remove_offset = 0;
std::list<Consumer*> cons;
...
void remove() {
// find lowest read point
long cons_offset = MAX_LONG;
for( auto p : cons ) {
cons_offset = std::min( cons_offset, atomic_load(&p->offset) );
}
// remove up to that point
while( cons_offset > remove_offset ) {
entry& e = q.read(remove_offset);
remove_offset += e.size();
q.remove( e.size() );
}
}
};
In what situation should we adopt state pattern?
I've been assigned to maintain a project, the project state machine was implemented by switch-case that are 2000+ lines long. It will be hard to expand function, so I would like to refactor it.
I'm surveying state design pattern, but I have some confusions.
A simple example:
1. Initial state "WAIT", wait user send download command
2. While user send download command, move to "CONNECT" state, connect to server
3. After connection is created, move to "DOWNLOADING" state, keep receive data from server
4. While the data download complete, move to "DISCONNECT", disconnect link with server
5. After disconnect, move to "WAIT" state, wait user send download command
A simple state machine pic
Method 1: Before I survey state pattern, I think a trivial method --- wrapper different state behavior in different function, use a function pointer array to point each state function, and change state by call function.
typedef enum {
WAIT,
CONNECT,
DOWNLOADING,
DISCONNECT
}state;
void (*statefunction[MAX_STATE])(void) =
{
WAITState,
CONNECTState,
DOWNLOADINGState,
DISCONNECTState
};
void WAITState(void)
{
//do wait behavior
//while receive download command
//statefunction[CONNECT]();
}
void CONNECTState(void)
{
//do connect behavior
//while connect complete
//statefunction[DOWNLOADING]();
}
void DOWNLOADINGState(void)
{
//do downloading behavior
//while download complete
//statefunction[DISCONNECT]();
}
void DISCONNECTState(void)
{
//do disconnect behavior
//while disconnect complete
//statefunction[WAIT]();
}
Method 2: The state pattern encapsulates different state and its behavior in different class (object-oriented state machine), uses polymorphism to implement different state behavior, and defines a common interface for all concrete states.
class State
{
public:
virtual void Handle(Context *pContext) = 0;
};
class Context
{
public:
Context(State *pState) : m_pState(pState){}
void Request()
{
if (m_pState)
{
m_pState->Handle(this);
}
}
private:
State *m_pState;
};
class WAIT : public State
{
public:
virtual void Handle(Context *pContext)
{
//do wait behavior
}
};
class CONNECT : public State
{
public:
virtual void Handle(Context *pContext)
{
//do connect behavior
}
};
class DOWNLOADING : public State
{
public:
virtual void Handle(Context *pContext)
{
//do downloading behavior
}
};
class DISCONNECT : public State
{
public:
virtual void Handle(Context *pContext)
{
//do disconnect behavior
}
};
I'm wondering whether the state pattern batter than function pointer in this case or not...
Using function pointer only also can improve readability (compare with switch-case), and more simple.
The state pattern will create several class, and more complex than using function pointer only.
What's the advantage of using state pattern?
Thanks for your time!
What's the advantage of using the state pattern?
First, one needs to notice, that both of the methods you've provided, are in fact examples of the very same pattern. One of the methods describes a function-based implementation, while the other one takes more of an object oriented approach.
That being said, the pattern itself has a few advantages:
It limits the number of states, a program can be in, and thus - eliminates undefined states,
It allows for easier expansion of the application, by adding new states, instead of refactoring the whole code,
From a company perspective, it is safe, even when multiple people work on the same class,
Since you tagged the question as related to c++, it is best to take into account what the language both gives and requires. While classes offer inheritance, a large number of classes can greatly increase the compilation time. Hence, when it comes to implementations, if your state machine is large, static polymorphism may be the way to go.
This question comes from:
C++11 thread doesn't work with virtual member function
As suggested in a comment, my question in previous post may not the right one to ask, so here is the original question:
I want to make a capturing system, which will query a few sources in a constant/dynamic frequency (varies by sources, say 10 times / sec), and pull data to each's queues. while the sources are not fixed, they may add/remove during run time.
and there is a monitor which pulls from queues at a constant freq and display the data.
So what is the best design pattern or structure for this problem.
I'm trying to make a list for all the sources pullers, and each puller holds a thread, and a specified pulling function (somehow the pulling function may interact with the puller, say if the source is drain, it will ask to stop the pulling process on that thread.)
Unless the operation where you query a source is blocking (or you have lots of them), you don't need to use threads for this. We could start with a Producer which will work with either synchronous or asynchronous (threaded) dispatch:
template <typename OutputType>
class Producer
{
std::list<OutputType> output;
protected:
int poll_interval; // seconds? milliseconds?
virtual OutputType query() = 0;
public:
virtual ~Producer();
int next_poll_interval() const { return poll_interval; }
void poll() { output.push_back(this->query()); }
std::size_t size() { return output.size(); }
// whatever accessors you need for the queue here:
// pop_front, swap entire list, etc.
};
Now we can derive from this Producer and just implement the query method in each subtype. You can set poll_interval in the constructor and leave it alone, or change it on every call to query. There's your general producer component, with no dependency on the dispatch mechanism.
template <typename OutputType>
class ThreadDispatcher
{
Producer<OutputType> *producer;
bool shutdown;
std::thread thread;
static void loop(ThreadDispatcher *self)
{
Producer<OutputType> *producer = self->producer;
while (!self->shutdown)
{
producer->poll();
// some mechanism to pass the produced values back to the owner
auto delay = // assume millis for sake of argument
std::chrono::milliseconds(producer->next_poll_interval());
std::this_thread::sleep_for(delay);
}
}
public:
explicit ThreadDispatcher(Producer<OutputType> *p)
: producer(p), shutdown(false), thread(loop, this)
{
}
~ThreadDispatcher()
{
shutdown = true;
thread.join();
}
// again, the accessors you need for reading produced values go here
// Producer::output isn't synchronised, so you can't expose it directly
// to the calling thread
};
This is a quick sketch of a simple dispatcher that would run your producer in a thread, polling it however often you ask it to. Note that passing produced values back to the owner isn't shown, because I don't know how you want to access them.
Also note I haven't synchronized access to the shutdown flag - it should probably be atomic, but it might be implicitly synchronized by whatever you choose to do with the produced values.
With this organization, it'd also be easy to write a synchronous dispatcher to query multiple producers in a single thread, for example from a select/poll loop, or using something like Boost.Asio and a deadline timer per producer.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
What is a good way of dealing with objects and having them talk to each other?
Up until now all my games hobby/student have been small so this problem was generally solved in a rather ugly way, which lead to tight integration and circular dependencies. Which was fine for the size of projects I was doing.
However my projects have been getting bigger in size and complexity and now I want to start re-using code, and making my head a simpler place.
The main problem I have is generally along the lines of Player needs to know about the Map and so does the Enemy, this has usually descended into setting lots of pointers and having lots of dependencies, and this becomes a mess quickly.
I have thought along the lines of a message style system. but I cant really see how this reduces the dependencies, as I would still be sending the pointers everywhere.
PS: I guess this has been discussed before, but I don't know what its called just the need I have.
EDIT: Below I describe a basic event messaging system I have used over and over. And it occurred to me that both school projects are open source and on the web. You can find the second version of this messaging system (and quite a bit more) at http://sourceforge.net/projects/bpfat/ .. Enjoy, and read below for a more thorough description of the system!
I've written a generic messaging system and introduced it into a handful of games that have been released on the PSP as well as some enterprise level application software. The point of the messaging system is to pass only the data around that is needed for processing a message or event, depending on the terminology you want to use, so that objects do not have to know about each other.
A quick rundown of the list of objects used to accomplish this is something along the lines of:
struct TEventMessage
{
int _iMessageID;
}
class IEventMessagingSystem
{
Post(int iMessageId);
Post(int iMessageId, float fData);
Post(int iMessageId, int iData);
// ...
Post(TMessageEvent * pMessage);
Post(int iMessageId, void * pData);
}
typedef float(*IEventMessagingSystem::Callback)(TEventMessage * pMessage);
class CEventMessagingSystem
{
Init ();
DNit ();
Exec (float fElapsedTime);
Post (TEventMessage * oMessage);
Register (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback* fpMethod);
Unregister (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback * fpMethod);
}
#define MSG_Startup (1)
#define MSG_Shutdown (2)
#define MSG_PlaySound (3)
#define MSG_HandlePlayerInput (4)
#define MSG_NetworkMessage (5)
#define MSG_PlayerDied (6)
#define MSG_BeginCombat (7)
#define MSG_EndCombat (8)
And now a bit of an explanation. The first object, TEventMessage, is the base object to represent data sent by the messaging system. By default it will always have the Id of the message being sent so if you want to make sure you have received a message you were expecting you can (Generally I only do that in debug).
Next up is the Interface class that gives a generic object for the messaging system to use for casting while doing callbacks. Additionally this also provides an 'easy to use' interface for Post()ing different data types to the messaging system.
After that we have our Callback typedef, Simply put it expects an object of the type of the interface class and will pass along a TEventMessage pointer... Optionally you can make the parameter const but I've used trickle up processing before for things like stack debugging and such of the messaging system.
Last and at the core is the CEventMessagingSystem object. This object contains an array of callback object stacks (or linked lists or queues or however you want to store the data). The callback objects, not shown above, need to maintain (and are uniquely defined by) a pointer to the object as well as the method to call on that object. When you Register() you add an entry on the object stack under the message id's array position. When you Unregister() you remove that entry.
That is basically it. Now this does have the stipulation that everything needs to know about the IEventMessagingSystem and the TEventMessage object... but this object should Not be changing that often and only passes the parts of information that are vital to the logic dictated by the event being called. This way a player doesn't need to know about the map or the enemy directly for sending events off to it. A managed object can call an API to a larger system also, without needing to know anything about it.
For example: When an enemy dies you want it to play a sound effect. Assuming you have a sound manager that inherits the IEventMessagingSystem interface, you would set up a callback for the messaging system that would accept a TEventMessagePlaySoundEffect or something of that ilk. The Sound Manager would then register this callback when sound effects are enabled (or unregister the callback when you want to mute all sound effects for easy on/off abilities). Next, you would have the enemy object also inherit from the IEventMessagingSystem, put together a TEventMessagePlaySoundEffect object (would need the MSG_PlaySound for its Message ID and then the ID of the sound effect to play, be it an int ID or the name of the sound effect) and simply call Post(&oEventMessagePlaySoundEffect).
Now this is just a very simple design with no implementation. If you have immediate execution then you have no need to buffer the TEventMessage objects (What I used mostly in console games). If you are in a multi-threaded environment then this is a very well defined way for objects and systems running in separate threads to talk to each other, but you will want to preserve the TEventMessage objects so the data is available when processing.
Another alteration is for objects that only ever need to Post() data, you can create a static set of methods in the IEventMessagingSystem so they do not have to inherit from them (That is used for ease of access and callback abilities, not -directly- needed for Post() calls).
For all the people who mention MVC, it is a very good pattern, but you can implement it in so many different manners and at different levels. The current project I am working on professionally is an MVC setup about 3 times over, there is the global MVC of the entire application and then design wise each M V and C also is a self-contained MVC pattern. So what I have tried to do here is explain how to make a C that is generic enough to handle just about any type of M without the need to get into a View...
For example, an object when it 'dies' might want to play a sound effect.. You would make a struct for the Sound System like TEventMessageSoundEffect that inherits from the TEventMessage and adds in a sound effect ID (Be it a preloaded Int, or the name of the sfx file, however they are tracked in your system). Then all the object just needs to put together a TEventMessageSoundEffect object with the appropriate Death noise and call Post(&oEventMessageSoundEffect); object.. Assuming the sound is not muted (what you would want to Unregister the Sound Managers.
EDIT: To clarify this a bit in regards to the comment below:
Any object to send or receive a message just needs to know about the IEventMessagingSystem interface, and this is the only object the EventMessagingSystem needs to know of all the other objects. This is what gives you the detachment. Any object who wants to receive a message simply Register(MSG, Object, Callback)s for it. Then when an object calls Post(MSG,Data) it sends that to the EventMessagingSystem via the interface it knows about, the EMS will then notify each registered object of the event. You could do a MSG_PlayerDied that other systems handle, or the player can call MSG_PlaySound, MSG_Respawn, etc to let things listening for those messages to act upon them. Think of the Post(MSG,Data) as an abstracted API to the different systems within a game engine.
Oh! One other thing that was pointed out to me. The system I describe above fits the Observer pattern in the other answer given. So if you want a more general description to make mine make a bit more sense, that is a short article that gives it a good description.
Hope this helps and Enjoy!
the generic solutions for communication between objects avoiding tight coupling:
Mediator pattern
Observer pattern
Here is a neat event system written for C++11 you can use. It uses templates and smart pointers as well as lambdas for the delegates. It's very flexible. Below you will also find an example. Email me at info#fortmax.se if you have questions about this.
What these classes gives you is a way to send events with arbitrary data attached to them and an easy way to directly bind functions that accept already converted argument types that the system casts and checks for correct conversion prior to calling your delegate.
Basically, every event is derived from IEventData class (you can call it IEvent if you want). Each "frame" you call ProcessEvents() at which point the event system loops through all the delegates and calls the delegates that have been supplied by other systems that have subscribed to each event type. Anyone can pick which events they would like to subscribe to, as each event type has a unique ID. You can also use lambdas to subscribe to events like this: AddListener(MyEvent::ID(), [&](shared_ptr ev){
do your thing }..
Anyway, here is the class with all the implementation:
#pragma once
#include <list>
#include <memory>
#include <map>
#include <vector>
#include <functional>
class IEventData {
public:
typedef size_t id_t;
virtual id_t GetID() = 0;
};
typedef std::shared_ptr<IEventData> IEventDataPtr;
typedef std::function<void(IEventDataPtr&)> EventDelegate;
class IEventManager {
public:
virtual bool AddListener(IEventData::id_t id, EventDelegate proc) = 0;
virtual bool RemoveListener(IEventData::id_t id, EventDelegate proc) = 0;
virtual void QueueEvent(IEventDataPtr ev) = 0;
virtual void ProcessEvents() = 0;
};
#define DECLARE_EVENT(type) \
static IEventData::id_t ID(){ \
return reinterpret_cast<IEventData::id_t>(&ID); \
} \
IEventData::id_t GetID() override { \
return ID(); \
}\
class EventManager : public IEventManager {
public:
typedef std::list<EventDelegate> EventDelegateList;
~EventManager(){
}
//! Adds a listener to the event. The listener should invalidate itself when it needs to be removed.
virtual bool AddListener(IEventData::id_t id, EventDelegate proc) override;
//! Removes the specified delegate from the list
virtual bool RemoveListener(IEventData::id_t id, EventDelegate proc) override;
//! Queues an event to be processed during the next update
virtual void QueueEvent(IEventDataPtr ev) override;
//! Processes all events
virtual void ProcessEvents() override;
private:
std::list<std::shared_ptr<IEventData>> mEventQueue;
std::map<IEventData::id_t, EventDelegateList> mEventListeners;
};
//! Helper class that automatically handles removal of individual event listeners registered using OnEvent() member function upon destruction of an object derived from this class.
class EventListener {
public:
//! Template function that also converts the event into the right data type before calling the event listener.
template<class T>
bool OnEvent(std::function<void(std::shared_ptr<T>)> proc){
return OnEvent(T::ID(), [&, proc](IEventDataPtr data){
auto ev = std::dynamic_pointer_cast<T>(data);
if(ev) proc(ev);
});
}
protected:
typedef std::pair<IEventData::id_t, EventDelegate> _EvPair;
EventListener(std::weak_ptr<IEventManager> mgr):_els_mEventManager(mgr){
}
virtual ~EventListener(){
if(_els_mEventManager.expired()) return;
auto em = _els_mEventManager.lock();
for(auto i : _els_mLocalEvents){
em->RemoveListener(i.first, i.second);
}
}
bool OnEvent(IEventData::id_t id, EventDelegate proc){
if(_els_mEventManager.expired()) return false;
auto em = _els_mEventManager.lock();
if(em->AddListener(id, proc)){
_els_mLocalEvents.push_back(_EvPair(id, proc));
}
}
private:
std::weak_ptr<IEventManager> _els_mEventManager;
std::vector<_EvPair> _els_mLocalEvents;
//std::vector<_DynEvPair> mDynamicLocalEvents;
};
And the Cpp file:
#include "Events.hpp"
using namespace std;
bool EventManager::AddListener(IEventData::id_t id, EventDelegate proc){
auto i = mEventListeners.find(id);
if(i == mEventListeners.end()){
mEventListeners[id] = list<EventDelegate>();
}
auto &list = mEventListeners[id];
for(auto i = list.begin(); i != list.end(); i++){
EventDelegate &func = *i;
if(func.target<EventDelegate>() == proc.target<EventDelegate>())
return false;
}
list.push_back(proc);
}
bool EventManager::RemoveListener(IEventData::id_t id, EventDelegate proc){
auto j = mEventListeners.find(id);
if(j == mEventListeners.end()) return false;
auto &list = j->second;
for(auto i = list.begin(); i != list.end(); ++i){
EventDelegate &func = *i;
if(func.target<EventDelegate>() == proc.target<EventDelegate>()) {
list.erase(i);
return true;
}
}
return false;
}
void EventManager::QueueEvent(IEventDataPtr ev) {
mEventQueue.push_back(ev);
}
void EventManager::ProcessEvents(){
size_t count = mEventQueue.size();
for(auto it = mEventQueue.begin(); it != mEventQueue.end(); ++it){
printf("Processing event..\n");
if(!count) break;
auto &i = *it;
auto listeners = mEventListeners.find(i->GetID());
if(listeners != mEventListeners.end()){
// Call listeners
for(auto l : listeners->second){
l(i);
}
}
// remove event
it = mEventQueue.erase(it);
count--;
}
}
I use an EventListener class for the sake of convenience as base class for any class that would like to listen to events. If you derive your listening class from this class and supply it with your event manager, you can use the very convenient function OnEvent(..) to register your events. And the base class will automatically unsubscribe your derived class from all events when it is destroyed. This is very convenient since forgetting to remove a delegate from event manager when your class is destroyed will almost certainly cause your program to crash.
A neat way to get a unique type id for an event by simply declaring a static function in the class and then casting it's address into an int. Since every class will have this method on different addresses, it can be used for unique identification of class events. You can also cast typename() to an int to get a unique id if you want. There are different ways to do this.
So here is an example on how to use this:
#include <functional>
#include <memory>
#include <stdio.h>
#include <list>
#include <map>
#include "Events.hpp"
#include "Events.cpp"
using namespace std;
class DisplayTextEvent : public IEventData {
public:
DECLARE_EVENT(DisplayTextEvent);
DisplayTextEvent(const string &text){
mStr = text;
}
~DisplayTextEvent(){
printf("Deleted event data\n");
}
const string &GetText(){
return mStr;
}
private:
string mStr;
};
class Emitter {
public:
Emitter(shared_ptr<IEventManager> em){
mEmgr = em;
}
void EmitEvent(){
mEmgr->QueueEvent(shared_ptr<IEventData>(
new DisplayTextEvent("Hello World!")));
}
private:
shared_ptr<IEventManager> mEmgr;
};
class Receiver : public EventListener{
public:
Receiver(shared_ptr<IEventManager> em) : EventListener(em){
mEmgr = em;
OnEvent<DisplayTextEvent>([&](shared_ptr<DisplayTextEvent> data){
printf("It's working: %s\n", data->GetText().c_str());
});
}
~Receiver(){
mEmgr->RemoveListener(DisplayTextEvent::ID(), std::bind(&Receiver::OnExampleEvent, this, placeholders::_1));
}
void OnExampleEvent(IEventDataPtr &data){
auto ev = dynamic_pointer_cast<DisplayTextEvent>(data);
if(!ev) return;
printf("Received event: %s\n", ev->GetText().c_str());
}
private:
shared_ptr<IEventManager> mEmgr;
};
int main(){
auto emgr = shared_ptr<IEventManager>(new EventManager());
Emitter emit(emgr);
{
Receiver receive(emgr);
emit.EmitEvent();
emgr->ProcessEvents();
}
emit.EmitEvent();
emgr->ProcessEvents();
emgr = 0;
return 0;
}
This probably does not only apply to game classes but to classes in the general sense. the MVC (model-view-controller) pattern together with your suggested message pump is all you need.
"Enemy" and "Player" will probably fit into the Model part of MVC, it does not matter much, but the rule of thumb is have all models and views interact via the controller. So, you would want to keep references (better than pointers) to (almost) all other class instances from this 'controller' class, let's name it ControlDispatcher. Add a message pump to it (varies depending on what platform you are coding for), instantiate it firstly (before any other classes and have the other objects part of it) or lastly (and have the other objects stored as references in ControlDispatcher).
Of course, the ControlDispatcher class will probably have to be split down further into more specialized controllers just to keep the code per file at around 700-800 lines (this is the limit for me at least) and it may even have more threads pumping and processing messages depending on your needs.
Cheers
Be careful with "a message style system", it probably depends on implementation, but usually you would loose static type checking, and can then make some errors very difficult to debug. Note that calling object's methods it is already a message-like system.
Probably you are simply missing some levels of abstraction, for example for navigation a Player could use a Navigator instead of knowing all about the Map itself. You also say that this has usually descended into setting lots of pointers, what are those pointers? Probably, you are giving them to a wrong abstraction?.. Making objects know about others directly, without going through interfaces and intermediates, is a straight way to getting a tightly coupled design.
Messaging is definitely a great way to go, but messaging systems can have a lot of differences. If you want to keep your classes nice and clean, write them to be ignorant of a messaging system and instead have them take dependencies on something simple like a 'ILocationService' which can then be implemented to publish/request information from things like the Map class. While you'll end up with more classes, they'll be small, simple and encourage clean design.
Messaging is about more than just decoupling, it also lets you move towards a more asynchronous, concurrent and reactive architecture. Patterns of Enterprise Integration by Gregor Hophe is a great book that talks about good messaging patterns. Erlang OTP or Scala's implementation of the Actor Pattern have provided me with a lot of guidance.
#kellogs suggestion of MVC is valid, and used in a few games, though its much more common in web apps and frameworks. It might be overkill and too much for this.
I would rethink your design, why does the Player need to talk to Enemies? Couldn't they both inherit from an Actor class? Why do Actors need to talk to the Map?
As I read what I wrote it starts to fit into an MVC framework...I have obviously done too much rails work lately. However, I would be willing to bet, they only need to know things like, they are colliding with another Actor, and they have a position, which should be relative to the Map anyhow.
Here is an implementation of Asteroids that I worked on. You're game may be, and probably is, complex.
I have a commercial application made with C,C++/Qt on Linux platform. The app collects data from different sensors and displays them on GUI. Each of the protocol for interfacing with sensors is implemented using singleton pattern and threads from Qt QThreads class. All the protocols except one work fine. Each protocol's run function for thread has following structure:
void <ProtocolClassName>::run()
{
while(!mStop) //check whether screen is closed or not
{
mutex.lock()
while(!waitcondition.wait(&mutex,5))
{
if(mStop)
return;
}
//Code for receiving and processing incoming data
mutex.unlock();
} //end while
}
Hierarchy of GUI.
1.Login screen.
2. Screen of action.
When a user logs in from login screen, we enter the action screen where all data is displayed and all the thread's for different sensors start. They wait on mStop variable in idle time and when data arrives they jump to receiving and processing data. Incoming data for the problem protocol is 117 bytes. In the main GUI threads there are timers which when timeout, grab the running instance of protocol using
<ProtocolName>::instance() function
Check the update variable of singleton class if its true and display the data. When the data display is done they reset the update variable in singleton class to false. The problematic protocol has the update time of 1 sec, which is also the frame rate of protocol. When I comment out the display function it runs fine. But when display is activated the application hangs consistently after 6-7 hours. I have asked this question on many forums but haven't received any worthwhile suggestions. I Hope that here I will get some help. Also, I have read a lot of literature on Singleton, multithreading, and found that people always discourage the use of singletons especially in C++. But in my application I can think of no other design for implementation.
Thanks in advance
A Hapless programmer
I think singleton is not really what you are looking for. Consider this:
You have (lets say) two sensors, each with its own protocol (frame rate, for our purpose).
Now create "server" classes for each sensor instead of an explicit singleton. This way you can hide the details of how your sensors work:
class SensorServer {
protected:
int lastValueSensed;
QThread sensorProtocolThread;
public:
int getSensedValue() { return lastValueSensed; }
}
class Sensor1Server {
public:
Sensor1Server() {
sensorProtocolThread = new Sensor1ProtocolThread(&lastValueSensed);
sensorProtocolThread.start();
}
}
class Sensor1ProtocolThread : public QThread {
protected:
int* valueToUpdate;
const int TIMEOUT = 1000; // "framerate" of our sensor1
public:
Sensor1ProtocolThread( int* vtu ) {
this->valueToUpdate = vtu;
}
void run() {
int valueFromSensor;
// get value from the sensor into 'valueFromSensor'
*valueToUpdate = valueFromSensor;
sleep(TIMEOUT);
}
}
This way you can do away with having to implement a singleton.
Cheers,
jrh.
Just a drive-by analysis but this doesn't smell right.
If the application is "consistently" hanging after 6-7 hours are you sure it isn't a resource (e.g. memory) leak? Is there anything different about the implementation of the problematic protocol from the rest of them? Have you run the app through a memory checker, etc.?
Not sure it's the cause of what you're seeing, but you have a big fat synchronization bug in your code:
void <ProtocolClassName>::run()
{
while(!mStop) //check whether screen is closed or not
{
mutex.lock()
while(!waitcondition.wait(&mutex,5))
{
if(mStop)
return; // BUG: missing mutex.unlock()
}
//Code for receiving and processing incoming data
mutex.unlock();
} //end while
}
better:
void <ProtocolClassName>::run()
{
while(!mStop) //check whether screen is closed or not
{
const QMutexLocker locker( &mutex );
while(!waitcondition.wait(&mutex,5))
{
if(mStop)
return; // OK now
}
//Code for receiving and processing incoming data
} //end while
}