c++ - Multithreaded console I/O -
i'm using console in multithreaded application. right now, accepts output (printf , like) , far have no issues. however, want able support console input well, , life gets complicated.
to forewarn, i'm unfamiliar more complicated nuances of working console input , output. experience in subject doesn't go further printf/cout, scanf/cin, , using setconsoletextattribute() change color (on windows).
i prefer keep program cross-compatible possible, i'm not opposed having write platform-specific code, long can find viable alternatives other platforms.
conceptually, i'd console run on it's own thread, can lock while waiting cin without freezing whole program or 1 of other threads. thread send console output thread output in clean manner (probably using thread-safe queue), , input console reads send command off appropriate thread.
my first problem while i'm typing input, output show in middle of i'm typing. solution handle reserve bottom line of console input, , have output go second last line, pushing input line down. how can this?
wellp, solved using pdcurses. in case else wants similar, here's how did it. first, initialize console thusly:
console::console(bool makeconsole) { if (makeconsole == false) return; if (self) throw ("you need 1 console - not make another!\n"); self = this; #ifdef win32 allocconsole(); #endif initscr(); inputline = newwin(1, cols, lines - 1, 0); outputlines = newwin(lines - 1, cols, 0, 0); if (has_colors()) { start_color(); (int = 1; <= color_white; ++i) { init_pair(i, i, color_black); } } else wprintw(outputlines, "terminal cannot print colors.\n"); scrollok(outputlines, true); scrollok(inputline, true); leaveok(inputline, true); nodelay(inputline, true); cbreak(); noecho(); keypad(inputline, true); initcommands(); hello("starting %s.\n", app_name); hellomore("version %i.%i.%i.\n\n", app_majorver, app_minorver, app_revision); } next, function responsible handling output. it's simple, don't need special keep thread-safe. might not have encountered issues it, easy fix slap mutex on it.
void console::sendformattedmsg(short prefixcolor, const char* prefix, short color, const char* format, ...) { if (!self) return; va_list args; va_start(args, format); if (has_colors()) { if (prefix) { wattron(outputlines, a_bold | color_pair(prefixcolor)); wprintw(outputlines, prefix); } if (color == color_white) wattroff(outputlines, a_bold); wattron(outputlines, color_pair(color)); vwprintw(outputlines, format, args); wattroff(outputlines, a_bold | color_pair(color)); } else { wprintw(outputlines, prefix); vwprintw(outputlines, format, args); } wrefresh(outputlines); va_end(args); } and finally, input. 1 required quite bit of fine-tuning.
void console::inputloop(void) { static string input; wattron(inputline, a_bold | color_pair(color_white)); wprintw(inputline, "\n> "); wattroff(inputline, a_bold | color_pair(color_white)); wprintw(inputline, input.c_str()); wrefresh(inputline); char c = wgetch(inputline); if (c == err) return; switch (c) { case '\n': if (input.size() > 0) { sendformattedmsg(color_white, "> ", color_white, input.c_str()); cprint("\n"); executecommand(&input[0]); input.clear(); } break; case 8: case 127: if (input.size() > 0) input.pop_back(); break; default: input += c; break; } } this run every frame same thread handles window messages. disabled wgetch()'s blocking behavior using nodelay(), eliminating need have console input running in it's own thread. disable echoing , echo input manually. enabling scrolling on input window allows me clear it's contents using simple "\n", replacing updated contents if user has typed anything. supports 1 expect simple, multi-threaded terminal capable typing input receiving output multiple threads.
Comments
Post a Comment