I'm trying to create a game using the terminal. I ask if the player is ready and then make a countdown with the code down below. The problem is that all input the user makes is added to the next input query the program makes. I'm looking for a way to discard the previous input or block it entirely during this function.
I could do a getchar loop, but that would need user input after the countdown (pressing enter) which I don't want.
void countdown(void){
printf("5\n");
sleep(1);
printf("4\n");
sleep(1);
printf("3\n");
sleep(1);
printf("2\n");
sleep(1);
printf("1\n");
sleep(1);
clearScreen(0); //clears terminal
}
You basically can't; The notion of "discarding user input during a certain amount of time" doesn't really make any sense for standard out- and input, consider the fact that your input might come from a file for instance (the problem here is that 'time' isn't really a concept that exists in any way in the standard in/output routines).
You'd need a terminal API for that, and there's nothing like that in the C standard library, although there are libraries that provide capabilities like that (but you already said you didn't want to use external libraries).
Since you are using a linux environment, you can try using tcflush()
Link to tcflush documentation
Here is a modified example of your code using tcflush. You can uncomment the bottom portion and see that everything entered during the countdown is cleared from the stdio buffer.
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
void main(){
char str[100];
printf("5\n");
sleep(1);
printf("4\n");
sleep(1);
printf("3\n");
sleep(1);
printf("2\n");
sleep(1);
printf("1\n");
sleep(1);
// arguments for tcflush:
// 0 is for stdin
// TCIFLUSH is to flush data received but not read
tcflush(0,TCIFLUSH);
// prove it works by uncommenting this code
// printf("fgets is waiting");
// fgets(str, sizeof(str), stdin);
// printf("%s", str);
// clearScreen(0); //clears terminal
}
One way would be to use a thread for the countdown.
The main code starts the countdown thread, then loops to get an input.
If the input function returns before the thread has terminated, or the wrong reply was entered, ignore the input and repeat the loop.
Related
I have written a simple C program that basically consists of an endless loop that counts upwards. During the loop, the user is asked for input- and here comes the tricky part: the loop should NOT be blocked while waiting on the user, but display his input as soon as he entered it:
int main(void){
int i;
char dec;
for(;;i++){
printf("%d\n", i);
sleep(5);
if(i==4 || i==8){
printf("Please enter Y or N\n");
dec = fgetc(stdin);
printf("%c\n", dec);
}
}
return 0;
}
I found a similiar question for Python here Python. So do I need to push the user interaction into a new thread with pthread or is there an easier option?
Thanks!
EDIT
int main(void){
int i=0;
char dec;
fd_set input_set;
for(;;i++){
printf("%d\n", i);
sleep(2);
if(i==4 || i==8){
FD_ZERO(&input_set ); /* Empty the FD Set */
FD_SET(0, &input_set); /* Listen to the input descriptor */
dec = select(1, &input_set, NULL, NULL, 0);
}
}
return 0;
}
What you want to do is only possible with system dependent libraries. For instance on Unix you would typically use ncurses to get from the user if they have pressed a button.
The reason it is system dependent is that asynchronous IO is not available for all file system streams. In particular User I/O blocks and that block is unavoidable.
If you are committed to having a multi-threaded program that still uses read/write system calls you would need to have two threads, one for I/O and one for everything else. On the everything else thread you could query some shared memory area and see if the I/O thread has written the correct type of data to this shared memory area.
If you are on linux only, check out this SO post : What are the differences between poll and select?
If you are on both and/or you already have pthreads, then use a separate thread.
If you are using Windows, maybe you can try to use keyboard hooks. See SetWindowsHookEx.
It will capture all the keyboard clicks with callback.
If you are usingLinux, maybe you can use this: Non-blocking keyboard read - C/C++
I have just had a really good use for multithreading. As such.... I have to learn multithreading. I have a very simple program:
void *listenloop(void *arg){
while (1){
Sleep(2000);
puts("testing 123\n");
}
return NULL;
}
int main(){
pthread_t listener;
pthread_create(&listener,NULL,listenloop,"foo");
char testinput[200];
while(1){
puts("Scanning: ");
scanf("%s",testinput);
puts("\n\n");
printf("You typed: %s: ",testinput);
}
}
The theory is that it waits for user input, echos it, all while periodically printing.
None to my surprise, actually (and presumably obviously to my betters in the matter) the output is "messed up."
Now I can think of several ways around this problem, but no actual solutions. How should something of this nature be implemented? Can it just be done by manipulating the output of the program after it is displayed to the user?
Thanks!
So just wrap the prints in pthread_mutex_lock/unlocks with a single pthread_mutex_t and you should be fine.
http://linux.die.net/man/3/pthread_mutex_lock
pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;
void *listenloop(void *arg){
while (1){
Sleep(2000);
pthread_mutex_lock(&mutex);
puts("testing 123\n");
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(){
pthread_t listener;
pthread_create(&listener,NULL,listenloop,"foo");
char testinput[200];
while(1){
pthread_mutex_lock(&mutex);
puts("Scanning: ");
pthread_mutex_unlock(&mutex);
scanf("%s",testinput);
pthread_mutex_lock(&mutex);
puts("\n\n");
printf("You typed: %s: ",testinput);
pthread_mutex_unlock(&mutex);
}
}
In your original code, there should be no "messed up" output (caused by threading, anyway) in that code as only the one thread (the main one) is doing any output.
The only thing the other thread does is infinitely loop with a delay of some sort.
Now that you've updated the question to output from the other thread then, yes, it is possible for the output to intermix.
There are several ways around this, two spring to mind immediately.
Have all output go through a series of functions which mutex-protect the output stream, such as mutexed_printf()/mutexed_puts() (which you'll need to provide) (a).
Do all output from one of the threads, meaning the other will have to send data to it via some means (inter-thread communications like a queue) - that way all output can be properly mixed, such as on newline boundaries.
(a) Also keep in mind that, if you want to mutex protect the output stream for the user input operation, you'll probably want to protect the puts/scanf atomically so that the testing output doesn't mess up your input (by outputting messages after the prompt but before/during your input). That won't be possible with a mutexed_puts() function, you'll need an expanded mutexed_prompt_and_input() one.
I thought I was doing something simple here, but C decided to go asynchronous on me. I'm not sure what's going on. Here's my code:
#include <stdio.h>
int main() {
printf("start");
sleep(5);
printf("stop");
}
When I compile and run, I notice that sleep(5) works like a charm. But the compiler decided it was a good idea to skip the first printf() and go out of order, so when running, the program waits for 5 seconds and then prints startstop.
What's the deal? My theory is that the program initiates the print operation with the shell, then continues with the program, leaving Bash to wait until the program is no longer busy to actually render the strings. But I really don't know.
Thanks
printf uses buffered output. This means that data first accumulates in a memory buffer before it is flushed to the output source, which in this case is stdout (which generally defaults to console output). Use fflush after your first printf statement to force it to flush the buffered data to the output source.
#include <stdio.h>
int main() {
printf("start");
fflush(stdout);
sleep(5);
printf("stop");
}
Also see Why does printf not flush after the call unless a newline is in the format string?
Try adding '\n' to your printf statements, like so:
#include <stdio.h>
int main() {
printf("start\n");
sleep(5);
printf("stop\n");
}
The compiler is not executing this out of order. Just the output is getting accumulated, and then displayed when the program exits. The '\n' will invoke the line discipline in the tty drivers to flush the output.
Read this Q&A, it explains it.
When you create a thread does it automatically start the thread function that's in the parameter?
I'm using
iret1 = pthread_create(&client[i++].tID, NULL, thread_function, NULL);
printf("Thread Created"); //for testing purposes
In my thread function I have a print statement at the very top. ex:
void *thread_function(void *arg){
printf("Entered thread function");
...
}
Instead of printing Entered thread function it prints Thread Created right after
And it doesn't print Entered thread function until I start another thread, is there a reason for this?
You need at least to add a newline \n at the end of every printf(3) format function, and often to call fflush(3), e.g. add a call to fflush(NULL); after each of your two printf ...
Don't forget that <stdio.h> functions are buffered. See setvbuf(3) function and man page.
The reason why your output is not printed as soon as you want it to be is that it is staying in the buffer of stdout.
And you probably have no guarantee on the output. The individual characters might perhaps be intermixed. Read unlocked_stdio(3) and flockfile(3) for details.
You may want to read (several times) some pthread tutorial...
PS you could consider using directly the write(2) syscall (without using any <stdio.h> function).
This program
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <windows.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
void INThandler(int);
int main(void)
{
signal(SIGINT, INThandler);
char data[128];
int n;
while((n=read(0, data, 128)) > 0)
{
if(data[n] = '\n') break;
}
data[n] ='\0';
printf("%s", data);
return 0;
}
void INThandler(int sig)
{
char c;
signal(sig, SIG_IGN);
printf("OUCH, did you hit Ctrl-C?\n"
"Do you really want to quit? [y/n] ");
c = getchar();
if (c == 'y' || c == 'Y')
exit(0);
else
signal(SIGINT, INThandler);
}
Doesn't handle ctrl-c, but terminates at that input.
If I replace everything between the handler install and the return by
while (1)
Sleep(1);
the handler function is called and works but I want to have the read() in there.
EDIT: Looking back at this program, I noticed that I have
if(data[n] = '\n') break;
I wrote '=' instead of '==', but by using the later, it doesn't work properly and I don't understand why. Shouldn't it be a comparison to detect '\n'?
Also, I messed around with the buffer, but I can't make keep the input if I hit CTRL-C.
The example code does not take into accounts two issues:
read() will abort it's work if its process receives a signal (see man 2 read)
It is only guaranteed for a few functions that they can be called savely from a signal handler function (see man 7 signal). printf()and getch() do not not belong to this set of "save" functions.
The first issue could be fixed using a more differentiated way to handle the value returned by read(). I should counts how much data had already been read, together with some smart adjustment of the buffer passed to read().
Regarding the second issue, read() and write() are the functions of choice to perform input/output to/from a signal handler as those are listed to be "save" functions by the man-page mentioned above.
It's because of the implementation of read(2) you use doesn't allow that. Here is what I get when I compile your program, execute it and press ^C:
$ ./program
^COUCH, did you hit Ctrl-C?
Do you really want to quit? [y/n] y
$
or if I answer n and enter some data:
$ ./program
^COUCH, did you hit Ctrl-C?
Do you really want to quit? [y/n] n
test
test
$
Since read(2) is a system call, it depends on the system you use. I use Linux (3.2.0-4-686-pae) and here it's behaving correctly. Maybe you should consider to use scanf(3) or fread(3) with stdio(3) instead, for the platform you're using (which I take to be win32)? Or also use a different implementation, like the ones from Cygwin or MinGW?