Reputation: 3448
I have a console application that prints on standard output. I want to implement the following behaviour:
At first I thought about doing it in other thread (one thread for printing, one for waiting for input), but I suppose it's useless in this case, because it's impossible to wait for an input in a thread.
So I found two libraries that might be able to do that:
I don't know either of them, so I am not sure which one I should learn to obtain a goal. Or maybe there is another, simpler solution?
OS: Unix
EDIT: g-makulik asked me to show, why it wasn't possible to write using threads insisting, that it is possible and indeed, it is, but I don't think this is how it should look like:
#include <pthread.h>
#include <iostream>
#include <string>
#include <stdio.h>
void* print_message_function(void *doPrint) {
bool* vDoPrint = (bool*) doPrint;
while (*vDoPrint) {
sleep(0.5);
std::cout << "Thread 1" << std::endl;
}
return NULL;
}
void* keyPressed(void* doPrint) {
bool* vDoPrint = (bool*) doPrint;
while (*vDoPrint) {
*vDoPrint = (char) getchar() == 'k' ? false : true;
std::cout << "THIS ISN'T DISPLAYED UNLESS 'k' PRESSED.";
}
return NULL;
}
int main(int argc, char* argv[]) {
pthread_t thread1, thread2;
int iret1, iret2;
bool doPrint = true;
iret2 = pthread_create(&thread2, NULL, print_message_function,
(void*) &doPrint);
iret1 = pthread_create(&thread1, NULL, keyPressed,
(void*) &doPrint);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
std::cout << "Thread 1 returns: " << iret1 << std::endl;
std::cout << "Thread 2 returns: " << iret2 << std::endl;
return 0;
}
Upvotes: 2
Views: 4211
Reputation: 1
It is possible to wait for keybord input from one thread while another one outputs to the same console. You just need to synchronize your threads (input/output) to obtain the functionality upon user inputs (e.g. using an event queue).
EDIT:
Using select()
or epoll()
with a timeout instead of separate threads might be a better choice on systems providing these system calls.
The ncurses lib will enable you to organize the console display in a window like manner (e.g. having separate panels to show the outputs and having kind of command (line) input). See Midnight Commander for an advanced sample what ncurses is able to do.
But as long you don't care about such separation for the echoed input in your application simple thread separation for input and output will work fine.
I can't tell anything about SMFL but this library seems to support windowing on a graphics level rather than a console.
Upvotes: 2
Reputation: 19273
SFML is something I never heard about before. I can't say it's a bad choice but a pretty unpopular one, so it comes with a good likeliness that the users of your program will have to install it just for it. I wouldn't go that route.
ncurses is a pretty common and good solution but I think it's too complex for your case. ncurses comes in very handy when you are doing more complex text I/O, like drawing on screen, assembling windows, handling mouse etc. For such a simple application, I think it may be a bit overkill. On the other hand, if you want to catch very specific keypresses (e.g. arrow keys or other keys not resulting in text input) or handle mouse, then ncurses will help you.
Another popular and lightweight choice is SDL (with its SDL_input library). Unlike the previous solution, it's solely input-oriented. It will allow you to catch keystrokes, mouse clicks and possibly other input events with great detail, in non-blocking manner. However, you usually install libsdl as a whole and though it's tiny, I'm not sure if all users of your applications will appreciate that. Well, unless they use games which commonly use SDL.
And finally, you could implement such a simple thing yourself. If you care about *nix only (and not portability to systems like Windows), you can set stdin
to non-blocking mode, and use repetitive non-blocking reads in the main loop to check for keypress. If your application does more waiting than actual processing between loop iterations, it may be better to use select()
instead to handle both delaying and waiting for an input.
I would avoid introducing threads for that sole reason as they're inefficient and usually introduce more problems than they solve. You should never use threaded blocking I/O if non-blocking I/O is feasible.
Upvotes: 0
Reputation: 111
I've used ncurses before and while the following solution may not be the prettiest, it should work.
Ncurses allows you to put input into 'no-delay' mode. This makes getch()
, which reads a character from input, non-blocking and it will immediately return ERR if user has not pressed anything.
You can wait for the standard input file descriptor to see if the input file descriptor is ready for reading. That is, select()
or epoll()
or whatever you want. If you have to do something every 2 seconds, you can just put that time to select()
or epoll()
. If you do get a keypress, you can then decide whatever you want to do with it.
This solution needs no multithreading.
I have no knowledge of SFML so I don't know if it would make this any easier. Ncurses is a C-library which may or may not be convenient for a C++ application. If you have man pages installed, you probably can see documentation on any ncurses function directly (for example, man getch
).
Upvotes: 0