2

I have 2 threads: one of them is constantly cout'ing to the console some value, let's say increments an int value every second - so every second on the console is 1,2,3... and so on.

Another thread is waiting for user input - with the command cin.

Here is my problem: when I start typing something, when the time comes to cout the int value, my input gets erased from the input field, and put into the console with the int value. So when I want to type in "hello" it looks something like this:

1
2
3
he4
l5
lo6
7
8

Is there a way to prevent my input from getting put to the console, while other thread is writing to the console?

FYI this is needed for a chat app at client side - one thread is listening for messages and outputs this message as soon as it comes in, and the other thread is listening for user input to be sent to a server app.

Ziarno
  • 7,366
  • 5
  • 34
  • 40
  • 1
    Then the only thing you can do is to make the system receive the message only after you have typed/sent your message (Make it a single thread instead of two) – Aswin Murugesh Aug 10 '13 at 09:23
  • @Aswin well but then in the chat app you'd only be able to receive messages after you sent one... doesn't make much sense :) – Ziarno Aug 10 '13 at 09:36

6 Answers6

1

Usually the terminal itself echos the keys typed. You can turn this off and get your program to echo it. This question will give you pointers on how to do it Hide password input on terminal

You can then just get the one thread to handle output.

Community
  • 1
  • 1
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
0

If you are a slow typer, then the solution to your problem can be, as I said, making it a single thread, but that may make the app to receive only after it sends.

Another way is to increase your receiving thread's sleep time, which would provide you some more time to type (without interruption)

Aswin Murugesh
  • 10,831
  • 10
  • 40
  • 69
0

You could make a GUI (or use ncurses if you really want to work in the console). This way you avoid having std::cout shared by the threads.

stefaanv
  • 14,072
  • 2
  • 31
  • 53
0

I think you could solve this problem with a semaphore. When you have an incoming message you check to see if the user is writing something. If he does you wait until he finishes to print the message.

aiked0
  • 38
  • 5
  • hmm that might be a solution, but how can you detect if user is typing something? – Ziarno Aug 10 '13 at 10:27
  • I don't if you can do that using cin or scanf. When I read your problem I thought that the solution would be to have a common buffer for both output and input and a mutex to control it. If the user starts writing you enable the mutex and the incoming message has to wait to get into the buffer. The mutex is disabled when the user press ENTER or something like that. You print the buffer every second or something like that and you clean it. – aiked0 Aug 10 '13 at 10:52
0

Is there a way to prevent my input from getting put to the console, while other thread is writing to the console?

It is the other way around. The other thread shouldn't interrupt the display of what you are typing.

Say you have typed "Hel" and then a new message comes in from the other thread. What do you do? How should it be displayed?

  1. Totally disable echoing of what you type and only display it after you hit enter. In this way you can display messages from the different threads properly, in an atomic fashion. The big drawback is that you cannot see what you have typed already... :(

  2. You immediately echo what you type. When the new message comes in, you undo the "Hel", print the new message and print again "Hel" on a new line and you can continue typing. Doable but a bit ugly.

  3. You echo what you type in a separate place. That is, you split somehow the display. In one place you display the posted/received messages in order; and in another place you display what you are typing. You either need a GUI or at least some console library to do this. This would be the nicest solution but perhaps the most difficult to port to another OS due to the library dependencies.

In any case, you need a (preferably internally) synchronized stream that you can safely call from different threads and can write strings into it atomically. That is, you need to write your own synchronized stream class.

Hope this helps.

Ali
  • 56,466
  • 29
  • 168
  • 265
0

Well i recently solved this same issue with a basic workaround. This might not be the #1 solution but worked like a charm for me, as a newbie;

 #include <iostream>    // I/O
 #include <Windows.h>   // Sleep();
 #include <conio.h>     // _getch();
 #include <string>      // MessageBuffer
 #include <thread>      // Thread
 using namespace std;

 void ThreadedOutput();
 string MessageBuffer;  // or make it static

 void main()
 {
    thread output(ThreadedOutput); // Attach the output thread
    int count = 0;
    char cur = 'a'; // Temporary at start
    while (cur != '\r')
    {
        cur = _getch(); // Take 1 input
        if (cur >= 32 && cur <= 126) // Check if input lies in alphanumeric and special keys
        {
            MessageBuffer += cur; // Store input in buffer
            cout << cur; // Output the value user entered
            count++;
        }
        else if (cur == 8) // If input key was backspace
        {
            cout << "\b \b"; // Move cursor 1 step back, overwrite previous character with space, move cursor 1 step back
            MessageBuffer = MessageBuffer.substr(0, MessageBuffer.size() - 1); // Remove last character from buffer
            count--;
        }
        else if (cur == 13) // If input was 'return' key
        {
            for (int i = 0; i < (signed)MessageBuffer.length(); i++) // Remove the written input
                cout << "\b \b";
            // "MessageBuffer" has your input, use it somewhere
            MessageBuffer = ""; // Clear the buffer
        }
     }
     output.join(); // Join the thread
 }

 void ThreadedOutput()
 {
    int i = 0;
    while (true)
     {
        for (int i = 0; i < (signed)MessageBuffer.length(); i++) // Remove the written input
            cout << "\b \b";
        cout << ++i << endl; // Give parallel output with input
        cout << MessageBuffer; // Rewrite the stored buffer
        Sleep(1000); // Prevent this example spam
     }
 }
user3762712
  • 77
  • 1
  • 8