Sign in to follow this  
Kenster

Thread here, Thread there. Best suggestion?

Recommended Posts

Kenster    100
Hello everyone, over the course of years now, I have put some posts into here about my MMO. I have started from scratch with all my knowledge, and I have finally got something very stable running. My question comes here. Basically, I set up my world in a Grid. The Grid then parses between 8 threads (CPU Core # * 2) and then I run update() in those regions. Each region has a Queue of packets to send, and contains each Entity in game. Which is working great. The problem I forsee now is I want to keep the Database saving on its own thread. So really, it can max at 25% and I don't care. Either way, I can forsee myself having Threading issues here. I want to avoid locks because halting the Region Update could have some very harsh effects on proformence. I was thinking of a few things. A) Bool control ---- Basically just have IsSaving = true when it is, and the Update on that specific character will be skipped. Or even the reverse. If action is being made on that Character, then skip the Update. B) Have some type of locking. Again, I can see this being very poor. C) A queue for each Character. Basically, if a player wants an Item, we send a Delagte into the Queue. When its his turn from the Region to update, we run the Queue (Maybe even limit to ovoid over time in one Entity). We then can know simply if we can or cannot update if that Queue is being used. (If there is no Queue, there is no action for that player). I need some suggestions. I don't need any help on slowing down the updates or what to update when but any suggestions of communication between Character Data such as Items/Skills/Location would be nice. Any advice, or experience in the field would be wonders of help! Thanks all! Ken

Share this post


Link to post
Share on other sites
frob    44976
Have you done much development with multiprocessing/multithreading code?

If not, I strongly suggest you learn it in separate projects before trying to put it in your engine.

Just as you made many small programs to learn the language before jumping in to your current project, you need to know the fundamentals of multiprocessing before integrating it to your engine.

All of your questions you asked will be answered in the course of learning how multiprocessing works. They could each be addressed with spinlocks, interlocks, or lockless mechanisms, but you need to understand them before you can really use them.

Share this post


Link to post
Share on other sites
Nox_7bitfaster    100
Well I know two different approaches:

-If consistent of the whole world is very important you have to halt the whole world for the save cycle => threading has no advantage for the saving cycle afaik.

-If the data in the database (db) are allowed to be a bit inconsistent you use a db which supports threading and multiple clients. Then you send important events directly to the db as a query (things like something is created or destroyed) and less important/very volatile information like a position of an object is saved to the db less frequently => This way you dont have to care about a object-thread -> database-thread datatransport. Used by some MMORPG afaik.

Share this post


Link to post
Share on other sites
hplus0603    11356
If checkpointing the whole world is necessary, you probably want to save in a copy-on-write manner. Under Linux, this can efficiently be done using fork(). Make sure all threads are paused briefly, then fork(), then re-start the threads in the parent, while the child (now being in a consistent state) can save to database however it wants. Linux will only use new physical memory for this new process for the pages that the parent process changes after the fork(), so if most state doesn't change often, this is highly efficient.

Otherwise, I recommend a generic worker queue. When an object updates itself, and needs to checkpoint its state, queue a work item to save the new state of that object to the database. You can couple this with an object cache that keeps the object reference alive until the state has been checkpointed, if you want to avoid a read-after-write re-ordering hazard, as long as objects are only being mutated from a single physical process at a time. Here's how it would work:

1) Get object from cache. If not in cache, cache reads from database
2) Mutate object
3) Add a "hold" on the object in the cache, so it won't get purged
4) Enqueue object write request on worker queue
5) In worker queue completion callback, remove the "hold" on the object, so cache can purge it if desired

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this