Существует четыре допустимых комбинации значений O_RDONLY
, O_WRONLY
и O_NONBLOCK
флага. Рассмотрим их все по очереди.
open(const char *path, O_RDONLY);
В этом случае вызов open
блокируется, он не вернет управление программе до тех пор, пока процесс не откроет этот FIFO для записи. Это похоже на первый пример с командой cat
.
open(const char *path, O_RDONLY | O_NONBLOCK);
Теперь вызов open
завершится успешно и вернет управление сразу, даже если канал FIFO не был открыт для записи каким-либо процессом.
open(const char *path, O_WRONLY);
В данном случае вызов open
будет заблокирован до тех пор, пока процесс не откроет тот же канал FIFO для чтения.
open(const char *path, O_WRONLY | O_NONBLOCK);
Этот вариант вызова всегда будет возвращать управление немедленно, но если ни один процесс не открыл этот канал FIFO для чтения, open
вернет ошибку, -1, и FIFO не будет открыт. Если есть процесс, открывший FIFO для чтения, возвращенный файловый дескриптор может использоваться для записи в канал FIFO.
Примечание
Обратите внимание на асимметрию в использовании O_NONBLOCK
с O_RDONLY
и O_WRONLY
, заключающуюся в том, что неблокирующий вызов open
для записи завершается аварийно, если ни один процесс не открыл канал для чтения, а неблокирующий вызов open
для чтения не возвращает ошибку. На поведение вызова close
флаг O_NONBLOCK
влияния не оказывает.
Выполните упражнение 13.11.
Упражнение 13.11. Открытие файлов FIFO
Теперь рассмотрим, как можно использовать поведение вызова open
с флагом, содержащим O_NONBLOCK
, для синхронизации двух процессов. Вместо применения нескольких программ-примеров вы напишите одну тестовую программу fifo2.c, которая позволит исследовать поведение каналов FIFO при передаче ей разных параметров.
1. Начните с заголовочных файлов, директивы #define
и проверки правильности количества предоставленных аргументов командной строки:
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/my_fifo"
int main(int argc, char *argv[]) {
int res;
int open_mode = 0;
int i;
if (argc < 2) {
fprintf(stderr, "Usage: %s
O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv);
exit(EXIT_FAILURE);
}
2. Полагая, что программа передает тестовые данные, вы задаете параметр open_mode
из следующих аргументов:
for(i = 1; i
if (strncmp(*++argv, "O_RDONLY", 8) == 0) open_mode |= O_RDONLY;
if (strncmp(*argv, "O_WRONLY", 8) == 0) open_mode |= O_WRONLY;
if (strncmp(*argv, "O_NONBLOCK", 10) == 0) open_mode |= O_NONBLOCK;
}
3. Далее проверьте, существует ли канал FIFO, и при необходимости создайте его. Затем FIFO открывается, и пока программа засыпает на короткое время, выполняется результирующий вывод. В заключение FIFO закрывается.
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Gould not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIF0\n", getpid());
res = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), res);
sleep(5);
if (res != -1) (void)close(res);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
Как это работает
Эта программа позволяет задать в командной строке комбинации значений O_RDONLY
, O_WRONLY
и O_NONBLOCK
, которые вы хотите применить. Делается это сравнением известных строк с параметрами командной строки и установкой (с помощью |=
) соответствующего флага при совпадении строки. В программе используется функция access
, проверяющая, существует ли уже файл FIFO, и создающая его при необходимости.
Никогда не уничтожайте FIFO, т.к. у вас нет способа узнать, не использует ли FIFO другая программа.
O_RDONLY и O_WRONLY без O_NONBLOCK
Теперь у вас есть тестовая программа, и вы можете проверить комбинации пар. Обратите внимание на то, что первая программа, считыватель, помещена в фоновый режим.
$ ./fifo2 O_RDONLY &
[1] 152
Process 152 opening FIFO
$ ./fifo2 O_WRONLY
Читать дальше