This is the code sample from "man select" plus a few lines to read an actual file which is being written to. I suspected that when the ./myfile.txt
is written to, select
would return that it can now read from that fd. But what happens is that select constantly returns in the while loop so long as the txt file exists. I want it to only return when new data is written to the end of the file. I thought that is how it should work.
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
int fd_file = open("/home/myfile.txt", O_RDONLY);
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(fd_file, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
while (1)
{
retval = select(fd_file+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");
}
exit(EXIT_SUCCESS);
}
select() works by blocking until something happens on a file descriptor (aka a socket). What's 'something'? Data coming in or being able to write to a file descriptor -- you tell select() what you want to be woken up by.
The select() function tests file descriptors in the range of 0 to nfds-1. If the readfds argument is not a null pointer, it points to an object of type fd_set that on input specifies the file descriptors to be checked for being ready to read, and on output indicates which file descriptors are ready to read.
On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds).
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.
Disk files are always ready to read (but the read might return 0 bytes if you're already at the end of the file), so you can't use select()
on a disk file to find out when new data is added to the file.
POSIX says:
File descriptors associated with regular files shall always select true for ready to read, ready to write, and error conditions.
Also, as cnicutar pointed out in a now-deleted post, in general, you have to initialize the FD_SET on each iteration. In your code, you are monitoring one fd, and that fd is always ready, so the FD_SET is not in fact changing. However, if you have 5 decriptors to monitor, and select
detects that only one is ready, then on the next iteration, only that one descriptor would be monitored (unless you reset the FD_SET). This makes using select
tricky.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With