I/O in Dedicated Server consoles

Started by
3 comments, last by BaShildy 21 years, 5 months ago
Last year I wrote a 16-player multiplayer internet client-server game. I wrote a dedicated server that is console based. The command system was efficent so that an administrator could do anything within a few keystrokes. The weak point in the server was in its I/O. Everything was outputted using printf, in a multithreaded environment. If two threads were trying to write to the console simultaneously, the text would become jarbled. Also, I was using directinput for input, which unfortunately caused the input text to appear jarbled if a thread tried to output while the admin was typing. The one advantage it did have was that it was non-blocking. This became really important, as my first way of doing input caused the server to block until the input was complete. The input was reconized fine, but would appear to be a mess in the console to the viewer. In my current project, I would like to have a bottom line reserved solely for input. I have seen this before where the input line was one color, and the output was another. I am writing the server for windows, but I plan to port to Linux, so a crossplatform sollution would be excellent. I believe using wincon is the sollution, but I wasn't able to find any example source on google. My goal is to have my own backbuffer system and colorization to make server administration much more pleasent than the common "forced scrolling" that is normally used. This will allow me to do menus and scoreboards that update in real time, which is something I really would like to do. Doing this using a GUI isn't an option unfortuantely. Anyone have any code or resources that could help for this situation? - Kevin "BaShildy" King Game Programmer: DigiPen www.mpogd.com [edited by - BaShildy on October 17, 2002 12:48:23 AM]
- Kevin "BaShildy" KingGame Programmer: DigiPenwww.mpogd.com
Advertisement
The only way to stop the text garbling is to use synchronization. If the performance delay of doing the printf is too long, then you can synchronize access to a queue and place the text in there (just a mutex & memcpy then).

Unfortunately high-performance and portability are diametrically opposed goals. Acquiring and releasing a mutex isn''t too cheap either. On Win32 you can use a critical section which is faster and works correctly for this case.

A portable solution is to use sockets Send data from one thread to the other over a socket, then it''s guaranteed to be queued up and synchronized. It''s important that the message send is performed with one write call. Avoid using printf/sprintf (and other C library functions) and you can avoid some multi-threading issues (multi-thread versions of those sometimes take a global mutex). You could write your own routines that are thread-safe and do not require any locking (I have one to convert a float to a string).

All of this is only necessary if the IO delay is too high to tolerate. The over-all performance will be lower using a queue''ing method, but it lets you off-load the IO handling to another thread.

If you use a windowing system, these sorts of things are necessary to maintain a good response from the system. You''d be doing all the hard work involved with a multi-threaded GUI, without the benefit of having one The IO delay of updating a windowing system is usually higher than outputting text to the console, so it become important to have a queue''ing system with that sort of setup.

Sometimes you don''t need/want a queue, you can just stuff data in a hole, and have the UI thread periodically update the screen. However, this easier solution won''t work for your case because you have mutliple threads generating streaming data. It doesn''t get any harder than that!
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:Original post by Magmai Kai Holmlor
The only way to stop the text garbling is to use synchronization. If the performance delay of doing the printf is too long, then you can synchronize access to a queue and place the text in there (just a mutex & memcpy then).


Can you give a short example of doing this?

quote:Original post by Magmai Kai Holmlor
Unfortunately high-performance and portability are diametrically opposed goals. Acquiring and releasing a mutex isn''t too cheap either. On Win32 you can use a critical section which is faster and works correctly for this case.


I was using critical sections in many of my threads. Unfortuantely it was printf/cout that was not thread safe. A thread wouldn''t finish its timeslice until it was done calling printf, but the call is not guarenteed to complete when your done calling it. If my thread finished, and a new thread outputted as well, they would both be jarbled. So my outputing was thread safe, but the library was not.

quote:Original post by Magmai Kai Holmlor
A portable solution is to use sockets Send data from one thread to the other over a socket, then it''s guaranteed to be queued up and synchronized. It''s important that the message send is performed with one write call. Avoid using printf/sprintf (and other C library functions) and you can avoid some multi-threading issues (multi-thread versions of those sometimes take a global mutex).

You could write your own routines that are thread-safe and do not require any locking (I have one to convert a float to a string).


My problem isn''t that my I/O handling isn''t thread safe, its that my way of displaying it is. Using a global mutex may work, I only tried critical sections. The example I asked for above would be thread safe I think. Correct me if I''m wrong.


quote:Original post by Magmai Kai Holmlor
All of this is only necessary if the IO delay is too high to tolerate. The over-all performance will be lower using a queue''ing method, but it lets you off-load the IO handling to another thread.

If you use a windowing system, these sorts of things are necessary to maintain a good response from the system. You''d be doing all the hard work involved with a multi-threaded GUI, without the benefit of having one The IO delay of updating a windowing system is usually higher than outputting text to the console, so it become important to have a queue''ing system with that sort of setup.

Sometimes you don''t need/want a queue, you can just stuff data in a hole, and have the UI thread periodically update the screen. However, this easier solution won''t work for your case because you have mutliple threads generating streaming data. It doesn''t get any harder than that!


Exactly. I was incorrect using the stuff data in a hole using printf method. It was my first multithreading program, and I learned a lot. Most suprisingly, the program is functional and working despite this problem :/

The performance isn''t a big deal. Right now, my performance is excellent (400,000 updates per second if ran without timeslice yielding). I would like the cleaneast, most elegant sollution possible. I can live with a win32 only sollution, I''ll have to write some Linux specific code in the future anyways. Might as well write some more so I can feel more confortable with the environment.





- Kevin "BaShildy" King
Game Programmer: DigiPen
www.mpogd.com
- Kevin "BaShildy" KingGame Programmer: DigiPenwww.mpogd.com
quote:Original post by BaShildy
I was using critical sections in many of my threads. Unfortuantely it was printf/cout that was not thread safe. A thread wouldn''t finish its timeslice until it was done calling printf, but the call is not guarenteed to complete when your done calling it. If my thread finished, and a new thread outputted as well, they would both be jarbled. So my outputing was thread safe, but the library was not.

Are you using the multi-threaded version of the CRT (C run-time)?

quote:Original post by BaShildy
Original post by Magmai Kai Holmlor
The only way to stop the text garbling is to use synchronization. If the performance delay of doing the printf is too long, then you can synchronize access to a queue and place the text in there (just a mutex & memcpy then).

Can you give a short example of doing this?

I don''t think a short example is possible

Here''s a long one:

  class CriticalSection	{	private:		//Critical Sections should not be copied.		CriticalSection(const CCriticalSection& refCritSec);		CriticalSection& operator=(const CCriticalSection& refCritSec);	public:		inline CriticalSection()  {InitializeCriticalSection(&this->cs);}		inline ~CriticalSection() {    DeleteCriticalSection(&this->cs);}		inline void Lock()         {     EnterCriticalSection(&this->cs);}		inline void Unlock()       {     LeaveCriticalSection(&this->cs);}		operator CRITICAL_SECTION&() {return(cs);}	protected:		CRITICAL_SECTION cs;	};		template<typename TSync = CriticalSection>		struct auto_sync			{			typedef typename TSync sync_type;			inline auto_sync(sync_type& Sync_) : sync(Sync_)				{				assert(&Sync_);				sync.Lock();				}			inline auto_sync(sync_type* pSync_) : sync(*pSync_)				{				assert(pSync_);				sync.Lock();				}			inline ~auto_sync()				{				sync.Unlock();				}			private:				sync_type& sync;			};struct console{std::queue<std::string> queue;CriticalSection lock;void write_text(const char* str);void print_text();};//call this in your threadsvoid console::write_text(const char* str){auto_sync gaurd(this->lock);queue.push_back(str);//this will copy str into a std::string} //auto_lock will automatically release the critical section here//periodically call this from your UI threadvoid console::print_text(){auto_sync gaurd(this->lock);while(!this->queue.empty())   {   //replace printf with GUI routines if you decide to use one   //e.g. TextOut (Win32 GDI)   printf("%s\n", queue.front().c_str());   queue.pop();   }}  
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Thanks so much for the long example
That will definately help me.

>> Are you using the multi-threaded version of the CRT (C run-time)?

I wasn''t. I''m going to lookup how to do that (should be easy I''m assuming). I didn''t know there was a multi-threaded CRT. That''s exactly what I needed, thanks.

And since noone posted about the colorization, I''m leeching some wincon example code that a friend worked on. Its probably a trivial topic, but when your pressed for time and can''t find any examples in over an hour you start to get slightly frusterated. I''ll post some source using it in the future.

- Kevin "BaShildy" King
Game Programmer: DigiPen
www.mpogd.com
- Kevin "BaShildy" KingGame Programmer: DigiPenwww.mpogd.com

This topic is closed to new replies.

Advertisement