I'm writing a server(mainly for windows, but it would be cool if i could keep it multiplatform) and i just use a normal console window for it. However, I want the server to be able to do commands like say text_to_say_here or kick playername, etc. How can i have a asynchronous input/output? I allready tried some stuff with the normal printf() and gets_s but that resulted in some really.... weird stuff.
I mean something like this 1
thanks.
Quick code to take advantage of C++11 features (i.e. cross-platform)
#include <atomic>
#include <thread>
#include <iostream>
void ReadCin(std::atomic<bool>& run)
{
std::string buffer;
while (run.load())
{
std::cin >> buffer;
if (buffer == "Quit")
{
run.store(false);
}
}
}
int main()
{
std::atomic<bool> run(true);
std::thread cinThread(ReadCin, std::ref(run));
while (run.load())
{
// main loop
}
run.store(false);
cinThread.join();
return 0;
}
You can simulate asynchronous I/O using threads, but more importantly, you must share a mutex between the two read/write threads in order to avoid any issues with a thread stepping on another thread, and writing to the console on top of the output of another thread. In other words std::cout
, std::cin
, fprintf()
, etc. are not multi-thread safe, and as a result, you will get an unpredictable interleaving pattern between the two operations where a read or write takes place while another read or write was already happening. You could easily end up with a read trying to take place in the middle of a write, and furthermore, while you're typing an input on the console, another writing thread could start writing on the console, making a visual mess of what you're trying to type as input.
In order to properly manage your asynchronous read and write threads, it would be best to setup two classes, one for reading, and another for writing. In each class, setup a message queue that will either store messages (most likely std::string
) for the main thread to retrieve in the case of the read thread, and for the main thread to push messages to in the case of the write thread. You may also want to make a special version of your read thread that can print a prompt, with a message pushed into its message queue by the main thread that will print a prompt before reading from stdin
or std::cin
. Both classes will then share a common mutex or semaphore to prevent unpredictable interleaving of I/O. By locking the common mutex before any iostream
calls (an unlocking it afterwards), any unpredictable interleaving of I/O will be avoided. Each thread will also add another mutex that is unique to each thread that can be used to maintain exclusivity over access to the class's internal message queue. Finally, you can implement the message queues in each class as a std::queue<std::string>
.
If you want to make your program as cross-platform as possible, I would suggest implementing this with either Boost::threads, or using the new C++0x std::threads libraries.
If you ditch the console window and use TCP connections for command and control, your server will be much easier to keep multi-platform, and also simpler and more flexible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With