сряда, 14 януари 2009 г.

Функцията "Select"

#include
#include
#include
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

Функцията select показва кои от дадените файлови дескриптори са готови за четене, писане или пък имат настъпили грешки. Ако условията (готов за четене/готов за писане/с настъпили грешки) са грешни за всички посочени файлови дескриптори, то select блокира, чака до посочения timeout интервал, докато някое от условията не стане вярно за поне един от файловите дескриптори. select поддържа обикновени файлове, терминални и псевдотерминални устройства, потоково-базирани файлове, FIFOs и канали (pipes). Поведението на select при дексриптори на други видове файлове е неопределено.
numfds – диапазонът от файлови дескриптори, които ще бъдат проверявани дали отговарят на някое от условията (т.е. проверяват се само дескрипторите в интервала от 0 до numfds – 1)
readfds – ако не е нулев указател, то сочи към обект от тип fd_set, който при извикването на функцията представлява множество от файлови дескриптори, които трябва да бъдат проверени за готовност за четене, а при изхода от функцията показва кои от тези файлови дескриптори действително са готови за четене
writefds – същото като readfds, само че за писане
exceptfds – при извикването на функцията това е множество от файлови дескриптори, които трябва да бъдат проверени дали имат настъпили грешки на тях, а при изхода от функцията са тези дескриптори, които наистина отговарят на условието да имат настъпили грешки
timeout – ако не е нулев указател, то сочи структура timeval, която определя максималния интервал за чакане. Ако в тази структура стойностите са 0, то select не блокира. Ако пък timeout е нулев указател, то select блокира, докато някакво събитие (например сигнал kill) не накара някой от дескрипторите да започне да отговаря на посоченото условие. Ако таймаутът изтече преди някой от файловите дескриптори да е готов, то select завършва успешно и връща 0.

struct timeval {
int tv_sec; // секунди
int tv_usec; // микросекунди
}

Ако readfds, writefds и exceptfds са нулеви указатели, а timeout не е, то select блокира за указаното време или докато не бъде прекъснат от сигнал. Ако readfds, writefds и exceptfds са нулеви указатели и timeout също е нулев указател, то select блокира за неограничено време, докато не бъде прекъснат от сигнал.
При грешка обектите, сочещи към readfds, writefds и exceptfds, не се променят. Ако таймаутът изтече преди даденото условие да стане вярно за някой от файловите дескриптори, всичките битове на обектите, сочещи към readfds, writefds и exceptfds, се установяват на 0.
select връща -1 при грешка, 0 при изтекъл таймаут, иначе общия брой файлови дескриптори, отговарящи на съответните условия.

Съществуват следните макроси за манипулация на множества от тип fd_set (които всъщност представляват множества от битове):

void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ZERO(fd_set *fdset);
int FD_ISSET(int fd, fd_set *fdset);

FD_SET добавя посочения файлов дескриптор fd в множеството fdset.
FD_CLR премахва файловия дескриптор fd от множеството fdset.
FD_ZERO изпразва fdset, т.е. установява всички битове на 0.
FD_ISSET връща ненулева стойност, ако fd присъства в множеството fdset, 0 в противен случай.

Ако fd е по-малко от 0 или по-голямо от FD_SETSIZE, поведението на тези макроси е неопределено. int FD_SETSIZE е макро, което връща максималния брой файлови дескриптори, за които един обект fd_set може да пази информация; по премълчаване тази стойност е 1024.

Пример за проста употреба на select:

/**********/
/* Select */
/**********/

/* Make the necessary includes and set up the variables. */

#include
#include
#include
#include
#define STDIN 0 // standard input descriptor

int main() {
struct timeval tv;
fd_set readfds;

// define the timeout to be 20 seconds and a half:
tv.tv_sec = 20;
tv.tv_usec = 500000;

// clear the fd_set:
FD_ZERO(&readfds);

// add STDIN to the fd_set:
FD_SET(STDIN, &readfds);

// don't care about writefds and exceptfds:

int result = select(STDIN + 1, &readfds, NULL, NULL, &tv);

switch(result) {
case -1:
fprintf(stderr, "An error has occured during select!\n");
return 1;
case 0:
fprintf(stderr, "\nTimeout has elapsed!\n");
return 1;
default:
if (FD_ISSET(STDIN, &readfds)) {

char buffer[128];
int nread;

nread = read(STDIN, buffer, 1024);
buffer[nread] = 0;
printf("Read %d bytes from keyboard: %s", nread, buffer);
}
}
return 0;
}

Няма коментари:

Публикуване на коментар