Make Message and Client pools thread-safe using ConcurrentDictionary#180
Make Message and Client pools thread-safe using ConcurrentDictionary#180CrossV4 wants to merge 1 commit into
Conversation
…and ConcurrentStack for avoiding calling Update function from another thread.
|
Thanks for the PR, Erol! Regarding the Additionally, a number of your code comments read like they were AI generated and they don't fit in with the rest of the code-base, and some of the XML doc comments (the Could you please remove those lines from the headers and do an "AI tone"/grammar/typo pass on your comments? (If English is not your first language I can also try to find some time to help with this.) I’m happy to take another look at the logic changes once that's done 🙂 |
|
uhh yess, i am a turkish guy i couldnt properly write a professional english so i wote the lines in turkish then i translate them with ai 😅😅. Okay, i will remove the command lines and i will try to write it withouit ai (but i dont think i will writte them professionally) |
Summary of Changes
I have developed a highly efficient, multi-threaded, and thread-safe networking architectural pattern for RiptideNetworking, specifically designed for high-concurrency projects like MMORPGs.
The Problem: Thread Contention & Race Conditions
When offloading network I/O operations to a dedicated background thread (e.g., executing
Server.Update()asynchronously to keep the main game loop responsive), serious race conditions occur. The primary culprit is Riptide’s internal message pool (Message.Create(),Message.Release()). Accessing the message pool concurrently from both the Main Thread (Game Logic) and the Background Thread (Network Loop) corrupts internal byte arrays, leading to network desynchronization, corrupted data, and server crashes.The Solution: The Command Pattern & Asynchronous Action Queue
To bridge the gap between the Main Thread and the Network Thread safely without expensive resource locking, I implemented a custom Command Pattern execution pipeline combined with a
ConcurrentQueue.INetworkCommandstructures and enqueue them into a thread-safeConcurrentQueue.Update()loop. To ensure server stability and prevent CPU spikes caused by a massive surge of packets, I integrated a Frame Budget Monitor using aStopwatch. If processing takes longer than the allocated frame time budget(MaxFrameMs), the execution breaks, deferred actions are carried over to the next frame, and a warning is logged.Server.Update()runs continuously on a high-priority background worker thread, throttled naturally to prevent CPU core exhaustion.Message message = Message.Create(MessageSendMode.Reliable, ServerToClientId.PromoResult);Why This is Vital for the Community
By enforcing this design, Riptide’s pooling mechanism (Message.Create) is only ever touched from a single thread sequence during actual processing, completely eliminating Riptide-pool-related Multi-Thread crashes. I wanted to share this architectural solution with the Riptide community to help anyone struggling to transition their dedicated servers to an asynchronous, high-performance, and crash-proof multi-threaded environment. Hope it helps!