If you are still stuck, then here is a short example using pselect
(set to not block, e.g. both fields of struct timespec
set to 0
). It simply uses an infinite loop to check pselect
to determine whether input is waiting to be read on stdin
. If so it reads the input and if the user entered a P
(or any string beginning with P
) P
is output, once per-second for a time period, before the resuming with either A
or B
(whatever was not displayed last before 'P').
I have the time period currently set to 10 sec.
for testing, just adjust the #define PERIOD 10
constant to change to whatever number of seconds you need (e.g. 60
in your case) I wasn't going to watch a minute each worth of A's
, B's
or P's
...
The use of pselect
is fairly straight forward. It is identical to select
except for the timeval
struct select
uses for time and select
has no sigmask
parameter. (irrelevant here) The key is to set both fields of the timespec
struct to 0
so that pselect
will not block waiting for input. You simply call it, and if the return is 1
, then you have input waiting. Then it's just a matter of reading the input (I chose fgets
so it would read and consume the trailing '\n'). Check whether the users entered P
(by simply checking the first character in buf
), if so, then begin a new period outputting P
, otherwise simply continue plodding along with your A
or B
output. There are additional comments inline below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <unistd.h>
#define MAXC 64 /* size of buffer for fgets */
#define PERIOD 10 /* no. of seconds for alternating period */
/* simple function calling pselect, returns 1 when input waiting */
int haveinput (int filedes)
{
fd_set set;
struct timespec timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = 0; /* timeout 0 - immediately return, */
timeout.tv_nsec = 0; /* if NULL, blocks indefinitely. */
return pselect (filedes + 1, &set, NULL, NULL, &timeout, NULL);
}
int main (void)
{
int c = 'A',
last = c; /* holds last 'A' or 'B' for pickup after 'P' */
unsigned long begin = time (NULL); /* begin seconds of period */
for (;;) { /* loop until 'q' entered or EOF */
unsigned long current = time (NULL); /* current seconds */
if (haveinput (STDIN_FILENO) == 1) { /* is input ready? */
char buf[MAXC] = ""; /* if so, get it! */
if (!fgets (buf, MAXC, stdin) || *buf == 'q')
break; /* if EOF or 'q' -- bail */
if (*buf == 'P') { /* if user entered 'P' */
c = 'P'; /* set c = 'P' */
begin = time (NULL); /* restart time period */
}
}
else {
putchar (c); /* if no imput read, output char */
fflush (stdout); /* output is buffered so fflush */
sleep (1); /* arbitrary second to wait */
}
if (current - begin >= PERIOD) { /* end of period reached */
if (last == 'A') /* if last was 'A' use 'B' */
c = last = 'B';
else /* otherwise use 'A' */
c = last = 'A';
begin = time (NULL); /* restart time period */
putchar ('\n');
}
}
putchar ('\n');
return 0;
}
(note: this is a 'nix specific solution. Windows does not provide sys/select.h
(nor does MinGW). While windows provides a version of select
through Winsock2.h
and lib Ws2_32.lib
it does not behave consistent with the implementation here.)
Example Use/Output
With an alternating period of 10 sec. instead of 60:
$ ./bin/pselect_abp
AAAAAAAAAAA
BBBBBBBBBBB
AAAAAAP
PPPPPPPPPPP
BBBBBBBBBBB
AAAAAAzz
AAAAA
BBBBBBBBBBB
AAAqA
Give it a try, look things over and let me know if you have further questions.