Timed reading in C (?)
Larry Philps
larry at hcr.UUCP
Thu Feb 18 00:37:55 AEST 1988
In article <469 at mv02.ecf.toronto.edu> ip at mv02.ecf.UUCP (Bevis Ip) writes:
>>What I want my program to do is wait a short while (like, say, 5 seconds
>>or so) for an user to type in something. If the user doesn't type in
>>anything after that time period, the program goes ahead and does something
>>else. But if the user has already started to type, the program waits and
>>lets him finish typing.
>>
>>What I'd like to know is how to do this in C. (By the way, I'm on BSD
>>Unix 4.3.) I want the user's terminal to stay in the canonical mode,
>>if possible.
>
>Took me a while to crank the following program up, seems like it's doing
>what you've asked. There're probably better ways in doing this, and I'm
>open for criticism. The code is pretty straight forward (I hope), so
>comments are minimal.
>
>bevis
>
> Program using signals, setjmp, longjmp ...
This can be done a little easier. The following two incomplete programs
should show you how. Since I did not write complete programs, I have
obviously not tested them, but you should get the idea.
/*
* Solution 1: Use select to wait for a specified period for input.
* When select returns, either the timeout has expired, or there is
* data to read. React appropriately.
*/
int fd, nbytes, nfound;
char buf[BUFFER_SIZE];
fdset readfds;
struct timeval timeout;
/*
* either this if reading standard input, or
* open the appropriate file and get a file
* descriptor for it.
*/
fd = 0;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = SLEEP_TIME;
timeout.tv_usec = 0;
nbytes = 1;
while (nbytes != 0) { /* End of File test */
nfound = select (1, &readfds, (int *)0, (int *)0, &timeout);
if (nfound < 0) {
perror("select");
exit(1);
}
if (nfound == 0) {
/*
* The timeout expired. There is no data to read
* so do what needs to be done in this case.
*/
.....
continue;
}
/*
* Select did not return an error, and the timeout did not
* expire. There must be data to read on the only file
* descriptor we told it to watch.
*/
ASSERT(FD_ISSET(fd, &readfds));
nbytes = read(fd, buf, sizeof(buf));
/*
* We have the data. Do something.
*/
...
}
/*
* Solution 2: Use non-blocking I/O so that the reads never hang.
* This has the disadvantage that if there is no data to read, then
* you sleep before trying again, thus creating a possible lag time
* between the time that the user types his input and the program sees
* it. The advantage is that it does not use select (an advantage you say!)
* and thus should even work on System V.
*/
int fd, nbytes;
char buf[BUFFER_SIZE];
/*
* either this if reading standard input, or
* open the appropriate file and get a file
* descriptor for it.
*/
fd = 0;
if (fcntl (fd, F_SETFL, FNDELAY) < 0) {
perror("fcntl: F_SETFL");
exit(1);
}
/*
* Give the user a chance to type something first.
* This is grotty.
*/
sleep(SLEEP_TIME);
/*
* Now non-blocking I/O is enabled on the file descriptor.
* Reads will not hang, so try one and if there is no data
* just sleep for a bit, then try again.
*/
while ((nbytes = read(fd, buf, sizeof(buf)) != 0) {
if (nbytes < 0 && errno == EWOULDBLOCK) {
/*
* No data for us now, do what needs to be done
* when the user has entered no input, then
* try again later.
*/
...
sleep(SLEEP_TIME);
continue;
}
/*
* We have the data. Do something.
*/
...
}
----
Larry Philps HCR Corporation
130 Bloor St. West, 10th floor Toronto, Ontario. M5S 1N5
(416) 922-1937 {utzoo,utcsri,decvax,ihnp4}!hcr!larry
More information about the Comp.unix.questions
mailing list