2016-04-17 6 views
2

Можно ли сделать неблокирующий ввод-вывод на трубе? fcntl не может установить O_NONBLOCK. Страница 918 интерфейса программирования Linux включает в себя таблицу «Семантика чтения n байтов из канала или FIFO (p)». В этой таблице показано поведение труб и FIFO с одним столбцом под названием O_NONBLOCK? Это означало бы, что вы можете установить флаг O_NONBLOCK в трубе. Это верно? Следующий код не может установить флаг, fcntl (2) не сообщает об ошибке.Неблокируемое считывание на трубе

#include <fcntl.h> 
#include <sys/wait.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 

#define SLEEP 1 

int 
main(int argc, char *argv[]) { 
    pid_t childPid; 
    int pfd[2]; 
    int nread, flags; 
    int c = 'a';  

    setbuf(stdout, NULL); 

    if (pipe(pfd) == -1) { 
     printf("error: pipe"); 
     exit(EXIT_FAILURE); 
    } 

    switch (childPid = fork()) { 
    case -1: 
     printf("error: fork"); 
     exit(EXIT_FAILURE); 
    case 0:   /* child */ 
     if (close(pfd[0]) == -1) { 
      printf("child: close pfd read"); 
      exit(EXIT_FAILURE); 
     } 
     sleep(SLEEP); 
     _exit(EXIT_SUCCESS); 
    default: 
     break; 
       /* parent falls through */ 
    } 
    if (close(pfd[1]) == -1) { 
     printf("parent: close pipe write"); 
     exit(EXIT_FAILURE); 
    } 

    flags = fcntl(pfd[0], F_GETFD); 
    flags |= O_NONBLOCK; 
    if (fcntl(pfd[0], F_SETFD, flags)) 
     perror("fcntl"); 

    /* verify flags set correctly */ 
    flags = fcntl(pfd[0], F_GETFD); 
    if (!(flags & O_NONBLOCK)) { 
     printf("failed to set O_NONBLOCK\n"); 
     exit(EXIT_FAILURE); 
    } 

    wait(NULL); 
    exit(EXIT_SUCCESS); 
} 
+0

Это похоже на ошибку в операции 'F_GETFD'. Я подтвердил, что это фактически устанавливает дескриптор неблокирования, и операции не блокируются, но 'F_GETFD' все равно возвращает ноль. –

ответ

7

Нет ничего особенного в трубке и O_NONBLOCK. Следующий пример работает так, как ожидалось. Я не проверял каждый retval от каждого вызова, чтобы сделать пример более читаемым. Приложения реального мира должны делать проверки.

#include <unistd.h> 
#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 

int main() 
{ 
    int fds[2]; 
    pid_t pid; 
    char buf[100]; 

    pipe(fds); 

    pid = fork(); 

    if (pid) 
    { 
     while (1) 
     { 
      memcpy(buf, "abcdefghi\0",10); 
      write(fds[1], buf, 10); 
      sleep(2); 
     } 
    } 
    else 
    { 
     int retval = fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK); 
     printf("Ret from fcntl: %d\n", retval); 
     while (1) 
     { 
      ssize_t r=read(fds[0], buf, 10); 
      printf("read: %d\n", r); 

      if (r > 0) 
      { 
       printf("Buffer: %s\n", buf); 
      } 
      else 
      { 
       printf("Read nothing\n"); 
       perror("Error was"); 
       sleep(1); 
      } 
     } 
    } 
} 

После написания моего примера я проверить ваш код и нашел:

flags = fcntl(pfd[0], F_GETFD); 
flags |= O_NONBLOCK; 
if (fcntl(pfd[0], F_SETFD, flags)) 

Пожалуйста, измените F_SETFD на F_SETFL, а также для работы ГЭТ. Вы бы не изменить file descriptor flags но file descriptor status flags :-)

От man 3 fcntl:

дескриптора файла флаги Следующие команды манипулировать флаги, связанные с файлом дескриптора. В настоящее время определяется только один такой флаг: FD_CLOEXEC, флаг close-on-exec. Если бит FD_CLOEXEC равен 0, дескриптор файла останется открытым через execve (2), в противном случае он будет закрыт.

статуса файла флаги Каждый открытый файл описания имеет определенные связанные состояния флагов, инициалов tialized открытым способом (2) и, возможно, модифицированный FCNTL(). Дублированный файл дескрипторы (сделанные с dup (2), fcntl (F_DUPFD), fork (2) и т. Д.) Относятся к тому же открытому описанию файла и, таким образом, имеют одинаковый статус файла .

F_SETFL (int) Установите флаги состояния файла на значение, заданное аргументом arg. Файл режим доступа (O_RDONLY, O_WRONLY, O_RDWR) и флаги создания файла (т. Е. O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) в arg игнорируются. В Linux эта команда может изменять только O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME и O_NONBLOCK флаги. невозможно изменить флаги O_DSYNC и O_SYNC; см. ОШИБКИ, ниже.

+0

Хорошо, поймите, Клаус, у меня было ощущение, что это было что-то глупое, что я делал. Спасибо за ваше время. – Tobin

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