Multithreading Simulator

Hi, in my fork I’ve used std::map<uint32, Train *> to store Train state because I needed persistent key to store for example current active train in UI.
Previouse std::vector suffered from index changes when a Train was added/removed.

The problem now is that since I store pointers to Train, I cannot deep copy it and so I need to lock mutex when drawing. So now it does not use multithreading efficently…

Hi,

Is it required to have a pointer to Train, else std::map<uint32, Train> would work, then you can easily deep copy it.

That could be an option. Then I would need to store vehicle activeTrain as a train ID and trains’s vehicles as a list of vehicle IDs.

My goal is to have 3 threads:

  • UI thread: deep copy state so does not lock during painting
  • Logic: core, does position calculation and all stuff
  • Network: UDP discovery, handshake timer not delayed by logic thread, manages connected clients list

Now how do I separate logic and network?
Do I need another boost io_context? And when I need to loop objects to send state refresh to clients should it be network thread or logic thread.

Ideally we want to lift burden of looping from the logic thread and put it in network thread.
But then we need to not wait on lock otherwise we might delay handshake timer.
So maybe we need to do some deep copy of state periodically also on network thread? How often?

Yes indeed, then it is easy deep copyable :slight_smile:

Yes you need an io_context per thread, it is possible to have multiple threads on a single io_context but they will act as workers then, so the will both do IO work which adds another level of complexity, you don’t want that here :wink:

All network IO must take place in the network thread, you could either do a periodic deep copy, or use e.g. boost::asio::post in the logic thread to post work to the network thread. (Traintastic server does that for: interface kernel thread ↔ event loop thread.)

If you want to send the full state periodically, you could e.g. make a deep copy of the state at the end of every N logic loops, when a copy is made post a call to the network thread so it knows the state data is updated then it can send it.

Hope I understand it correctly, if not please let me know.

Greetings,
Reinder

Good point. So there are 2 options:

  • lock from UI thread and deep copy state
  • deep copy state in logic thread and post to UI thread, this does not lock by maybe deep copies again to store in UI thread

I don’t know which is better.

Also now I store train’s vehicles as IDs which means many access to lookup ID and get vehicle object…

Then we could join Vehicle to VehicleState and Train to TrainState since it’s all dynamic now.

We should really discuss a refactoring plan!