问题
A thread where it prints values infinitely to console and a main thread which is taking user input from the console, but the input values are being mixed with the output of that thread.
C++ : cin while cout
Did give me a hint on how to move further but I was not able to come up with a solution of my own(as I am new to c++).
using namespace std;
mutex mtx;
void foo()
{
while (1)
{
usleep(1000000);
cout << "Cake\n";
}
}
int main()
{
mtx.lock();
thread t1(foo);
string x;
while (true)
{
cin >> x;
edit//fflush(stdin);
cout << x << "\n";
}
t1.join();
mtx.unlock();
return 0;
}
edit 1:
OK to be more precise what i really want is,
IN terminal(presently)
output:cake (which prints every second)
output:cake
output:cake
output:cake
input:hi
output:hicake (still yet to give the enter it echo's the input to console)
output:cake
what i actually want in terminal is input being independent of output
output:cake
output:cake
output:cake
input:hi
output:cake
output:cake
input:hi(waiting still for enter)
//and when enter is pressed it should print to the console
output:hi
output:cake
NOTE: disabling echo didn't help.
Edit 2: The answer posted by me has data processing where the concurrent operation stops on the given commands.
回答1:
Was able to come up with a solution using all the given inputs i hope this helps someone.
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <cstring>
#include <mutex>
#include <string>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
/// reads a character from console without echo.
int getChar()
{
struct termios oldattr;
tcgetattr(STDIN_FILENO, &oldattr);
struct termios newattr = oldattr;
newattr.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
const int ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
return ch;
}
class Console
{
private:
// mutex for console I/O
std::mutex _mtx;
// current input
std::string _input;
// prompt output
std::string _prompt;
public:
Console() {}
Console(const Console &) = delete;
Console &operator=(const Console &) = delete;
std::string read();
void write(const char *text, size_t size);
void write(const char *text) { write(text, strlen(text)); }
void write(const std::string &text) { write(text.c_str(), text.size()); }
};
std::string Console::read()
{
{ // activate prompt
std::lock_guard<std::mutex> lock(_mtx);
_prompt = "> ";
_input.clear();
std::cout << _prompt << std::flush;
}
enum
{
Enter = '\n',
BackSpc = 127
};
for (;;)
{
switch (int c = getChar())
{
case Enter:
{
std::lock_guard<std::mutex> lock(_mtx);
std::string input = _input;
_prompt.clear();
_input.clear();
std::cout << std::endl;
return input;
} // unreachable: break;
case BackSpc:
{
std::lock_guard<std::mutex> lock(_mtx);
if (_input.empty())
break;
_input.pop_back();
std::cout << "\b \b" << std::flush;
}
break;
default:
{
if (c < ' ' || c >= '\x7f')
break;
std::lock_guard<std::mutex> lock(_mtx);
_input += c;
std::cout << (char)c << std::flush;
}
break;
}
}
}
void Console::write(const char *text, size_t len)
{
if (!len)
return;
bool eol = text[len - 1] == '\n';
std::lock_guard<std::mutex> lock(_mtx);
// remove current input echo
if (size_t size = _prompt.size() + _input.size())
{
std::cout
<< std::setfill('\b') << std::setw(size) << ""
<< std::setfill(' ') << std::setw(size) << ""
<< std::setfill('\b') << std::setw(size) << "";
}
// print text
std::cout << text;
if (!eol)
std::cout << std::endl;
// print current input echo
std::cout << _prompt << _input << std::flush;
}
struct Flags //this flag is shared between both the threads
{
// flag: true then exit communication thread and main loop
bool exit;
// flag: true then start data processing
bool start;
// the mini console
Console console;
// constructor.
Flags() : exit(false), start(true) {}
};
void dataProc(Flags &shared)
{
int i = 0;
while (!shared.exit)
{
while (!shared.start)
{
if (shared.exit)
return;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
shared.console.write("Starting data processing.");
for (;;)
{
if (!shared.start || shared.exit)
{
shared.console.write("Data processing stopped.");
while (!shared.start || shared.exit)
{
if (shared.exit)
return;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
shared.console.write("Data processing restarted.");
}
std::this_thread::sleep_for(std::chrono::milliseconds(250));
{
std::ostringstream fmt;
fmt << "Cake " << ++i;
shared.console.write(fmt.str());
}
}
shared.console.write("Data processing done.");
shared.start = false;
}
}
void processInput(const std::string &input, Flags &shared)
{
if (strcasecmp(input.c_str(),"start")==0)
shared.start = true;
else if (strcasecmp(input.c_str(),"stop")==0)
shared.start = false;
else if (strcasecmp(input.c_str(),"exit")==0)
shared.exit = true;
else if (input.size())
shared.console.write("Wrong command!");
}
int main()
{
Flags shared;
std::thread threadProc(&dataProc, std::ref(shared));
while (!shared.exit)
{
shared.console.write("Commands accepted: start stop exit");
std::string input = shared.console.read();
processInput(input, shared);
}
threadProc.join();
return 0;
}
回答2:
I recommend locking your mtx
for the cout
as well as the cin
.
using namespace std;
mutex mtx;
void foo()
{
while (1)
{
usleep(1000000);
mtx.lock();
cout << "Cake\n";
mtx.unlock();
}
}
int main()
{
thread t1(foo);
string x;
while (true)
{
cin >> x;
mtx.lock();
cout << x << "\n";
mtx.unlock();
}
t1.join();
return 0;
}
来源:https://stackoverflow.com/questions/55414228/simultaneous-input-and-output-in-a-console