select
позволяет ждать ввода/вывода события вместо трать своё процессорное время на read
.
Таким образом, в вашем примере, основной цикл может выглядеть следующим образом:
for (;;)
{
int res;
char buf[256];
res = read(fileDescriptor1, buf, sizeof(buf));
if (res > 0)
{
printf("Read %d bytes from channel1\n", res);
}
res = read(fileDescriptor2, buf, sizeof(buf));
if (res > 0)
{
printf("Read %d bytes from channel2\n", res);
}
}
Если добавить код и запустить его, то можно заметить, что:
- Программа на самом деле делает то, что вы хочу - он читается из обеих труб.
- Загрузка процессора составляет 100% для одного ядра, то есть программа отбрасывает процессор даже тогда, когда нет данных для чтения.
Чтобы решить проблему, введены API-интерфейсы select
и poll
. Для select
нам нужно знать дескрипторы (мы делаем) и максимум из них.
Итак, давайте изменим код немного:
for (;;)
{
fd_set fds;
int maxfd;
FD_ZERO(&fds); // Clear FD set for select
FD_SET(fileDescriptor1, &fds);
FD_SET(fileDescriptor2, &fds);
maxfd = fileDescriptor1 > fileDescriptor2 ? fileDescriptor1 : fileDescriptor2;
select(maxfd + 1, &fds, NULL, NULL, NULL);
// The minimum information for select: we are asking only about
// read operations, ignoring write and error ones; and not
// defining any time restrictions on wait.
// do reads as in previous example here
}
При запуске усовершенствованного кода, процессор не будет потрачено впустую, как много, но вы заметите, что read
операция не выполняется, даже если там нет данные для конкретной трубы, но есть и для другого.
Чтобы проверить, что труба на самом деле данные, используйте FD_ISSET
после select
вызова:
if (FD_ISSET(fileDescriptor1, &fds))
{
// We can read from fileDescriptor1
}
if (FD_ISSET(fileDescriptor2, &fds))
{
// We can read from fileDescriptor2
}
Итак, после того, как соединение указанных выше, код будет выглядеть следующим образом:
for (;;)
{
fd_set fds;
int maxfd;
int res;
char buf[256];
FD_ZERO(&fds); // Clear FD set for select
FD_SET(fileDescriptor1, &fds);
FD_SET(fileDescriptor2, &fds);
maxfd = fileDescriptor1 > fileDescriptor2 ? fileDescriptor1 : fileDescriptor2;
select(maxfd + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(fileDescriptor1, &fds))
{
// We can read from fileDescriptor1
res = read(fileDescriptor1, buf, sizeof(buf));
if (res > 0)
{
printf("Read %d bytes from channel1\n", res);
}
}
if (FD_ISSET(fileDescriptor2, &fds))
{
// We can read from fileDescriptor2
res = read(fileDescriptor2, buf, sizeof(buf));
if (res > 0)
{
printf("Read %d bytes from channel2\n", res);
}
}
}
Итак, добавьте обработки ошибок, и вы будете установлены.
Вы прочитали страницу руководства? –
Да, он отображает подпись как int select (int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout); с nfds, являющимся наиважнейшим файловым дескриптором плюс 1. Не уверен, как определить, какой дескриптор файла поставить здесь. (Ив собранный файловый дескриптор - это то, что возвращает вызов low level open()), а readfds будут независимыми наборами файловых дескрипторов, которые просматриваются чтобы увидеть, становятся ли персонажи доступными. Итак, какую трубу поставить как аргументы nfds и как включить оба моих канала в качестве аргумента readfds? – GregH
И страница имеет пример http: //linux.die.net/man/2/select –