Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Input and output to the console window at the same time

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.

like image 295
Noah Avatar asked Jul 18 '11 17:07

Noah


3 Answers

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;
}
like image 200
Richard Dally Avatar answered Nov 18 '22 10:11

Richard Dally


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.

like image 20
Jason Avatar answered Nov 18 '22 11:11

Jason


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.

like image 1
n. 1.8e9-where's-my-share m. Avatar answered Nov 18 '22 11:11

n. 1.8e9-where's-my-share m.