2009-10-20 2 views
8

Мне нужна моя программа, написанная на чистом C, чтобы остановить выполнение, когда stdin закрыт.Как проверить, открыт ли stdin без блокировки?

Существует неопределенная работа, выполняемая в основном цикле программы, и я не могу использовать блокирующие проверки (например, getc()) там (данные не должны поступать на stdin - он остается открытым только в течение неизвестного времени).

Я намерен использовать описанную функциональность в реализации сетевого демона, размещенного в inetd, xinetd или их аналогах, - он должен выделять данные на stdout, пока соединение остается открытым и правильно завершает работу при его закрытии. Теперь моя программа убита службой хостинга, так как она не остановится после завершения соединения.

Интересно, если бы fctntl() с флагом O_NONBLOCK, примененным к дескриптору stdin, позволил бы мне использовать функцию read() в неблокирующем режиме? Должен ли я использовать select()?

P.S. Данные не допускаются, но могут поступать на stdin. Ответ на вопрос может быть способом неблокирующего считывания.

ответ

6

select() делает именно то, что вы хотите: сигнал о том, что операция (чтение в этом случае) в файловом дескрипторе (файл, сокет, что угодно) не будет блокироваться.

#include <stdio.h> 
#include <sys/select.h> 

int is_ready(int fd) { 
    fd_set fdset; 
    struct timeval timeout; 
    int ret; 
    FD_ZERO(&fdset); 
    FD_SET(fd, &fdset); 
    timeout.tv_sec = 0; 
    timeout.tv_usec = 1; 
    //int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 
    struct timeval *timeout); 
    return select(fd+1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0; 
} 

Теперь вы можете проверить дескриптор файла перед использованием, например, для того, чтобы опорожнить дескриптор файла:

void empty_fd(int fd) { 
    char buffer[1024]; 
    while (is_ready(fd)) { 
     read(fd, buffer, sizeof(buffer)); 
    } 
} 

В вашем случае, используйте fileno (STDIN), чтобы получить дескриптор файла из стандартного ввода:

if (is_ready(fileno(stdin))) { 
    /* read stuff from stdin will not block */ 
} 
+0

'poll' также точно соответствует требованиям OP, а его интерфейс немного проще, чем' select' при работе с небольшим фиксированным набором дескрипторов файлов. – ephemient

0

Что случилось с feof(stdin)?

+0

Это не сработает, если вы не зачитаете все данные. Как я могу прочитать все данные (например, мусор) без блокировки? – Basilevs

+0

EOF можно вводить в открытый stdin (например, через Ctrl-D в Linux). Это не означает, что stdin закрыт. –

1

Я не уверен, можно ли установить O_NONBLOCK на stdin, но select() или poll() определенно выполнит свою работу.

+0

Да, вы можете установить O_NONBLOCK на stdin. Если ваш stdin передан из другой программы, однако, эта программа может не обрабатывать дескриптор исходящего файла, который очень не блокируется. – ephemient

0

Да, вы можете использовать select (с нулевым тайм-аутом). Вам не нужно устанавливать файловую дескриптор неблокирующей, хотя - если select сообщает вам, что файловый дескриптор читабельен, то read на нем определенно не будет блокироваться.

Итак, описатель файла опроса 0 происходит с select, и если он доступен для чтения, read. Если read возвращает 0, значит, оно закрыто.

2

Интересно, если fctntl() с флагом O_NONBLOCK применяется для стандартного ввода дескриптора горе uld позволяет мне использовать функцию read() в неблокирующем режиме?

Запуск stdin с O_NONBLOCK имеет преимущества перед выбором. Select говорит, что есть некоторые данные, но не сколько. Есть моменты, когда вы хотите получить все доступные данные, но не блокировать, независимо от того, сколько в очереди. Запуск выбора для каждого персонажа кажется очень занятой работой ... O_NONBLOCK не работает для меня. Это внутренний флаг, который не отображается в большинстве драйверов tty.

Проверьте ioctl (..., FIONBIO). Кажется, что эта работа выполнена.

Смежные вопросы