Книга: UNIX: взаимодействие процессов

Глава 4

Глава 4

1. Если бы дескриптор fd[1] остался открытым в дочернем процессе при завершении родительского, его операция read для этого дескриптора не вернула бы признак конца файла, потому что дескриптор был бы еще открыт в дочернем процессе. Закрытие fd[1] гарантирует, что после завершения родительского процесса все его дескрипторы закрываются и вызов read для fd[1] возвращает 0.

2. Если поменять местами порядок вызовов, другой процесс сможет создать канал FIFO в промежутке между вызовами open и mkfifo, в результате чего последний вернет ошибку.

3. Если выполнить

solaris % mainopen 2>temp.stderr
/etc/ntp.conf > /myfile
solaris % cat temp.stderr
sh: /myfile: cannot create

мы увидим, что popen срабатывает успешно, но fgets считывает символ конца файла. Сообщение об ошибке записывается интерпретатором в стандартный поток сообщений об ошибках.

5. Измените первый вызов open, указав флаг отключения блокировки:

readfifo = Open(SERV_FIFO, O_RDONLY | O_NONBLOCK, 0);

Возврат из этого вызова произойдет немедленно, как и из следующего вызова open, поскольку канал уже открыт на чтение. Чтобы избежать ошибки при вызове readline, флаг O_NONBLOCK для дескриптора readfifo следует снять, перед тем как вызывать эту функцию.

6. Если клиент откроет свой канал на чтение перед открытием канала сервера, все зависнет. Единственный способ избежать блокировки заключается в вызове open для этих двух каналов в порядке, показанном в листинге 4.11, или в использовании флага отключения блокировки.

7. Исчезновение пишущего процесса воспринимается считывающим как конец файла.

8. В листинге Г.3 приведен текст соответствующей программы.

Листинг Г.З. Возвращает ли fstat количество байтов в канале FIFO?

//pipe/test1l.c
1  #include "unpipc.h"
2  int
3  main(int argc, char **argv)
4  {
5   int fd[2],
6   char buff[7];
7   struct stat info;
8   if (argc != 2)
9    err_quit("usage: test1 <pathname>");
10  Mkfifo(argv[1], FILE_MODE);
11  fd[0] = Open(argv[1], O_RDONLY | O_NONBLOCK);
12  fd[1] = Open(argv[1], O_WRONLY | O_NONBLOCK);
13  /* 4check sizes when FIFO is empty */
14  Fstat(fd[0], &info);
15  printf("fd[0]: st_size = %ldn", (long) info.st_size);
16  Fstat(fd[1], &info);
17  printf("fd[1]: st_size = %ldn", (long) info.st_size);
18  Write(fd[1], buff, sizeof(buff));
19  Fstat(fd[0], &info);
20  printf("fd[0]: st_size = %ldn", (long) info.st_size);
21  Fstat(fd[1], &info);
22  printf("fd[1]: st_size = %ldn", (long) info.st_size);
23  exit(0);
24 }

9. Вызов select возвращает информацию о возможности записи в дескриптор, но вызов write приводит к отправке сигнала SIGPIPE. Это описано в книге [24, с. 153-155]; когда возникает ошибка чтения или записи, select возвращает информацию о том, что дескриптор доступен, а собственно ошибка возвращается уже вызовами read или write. В листинге Г.4 приведен текст соответствующей пpoгрaммы.

Листинг Г.4. Что возвращает select при закрытии другого конца канала?

//pipe/test2.c
1  #include "unpipc.h"
2  int
3  main(int argc, char **argv)
4  {
5   int fd[2], n;
6   pid_t childpid;
7   fd_set wset;
8   Pipe(fd);
9   if ((childpid = Fork()) == 0) { /* child */
10   printf("child closing pipe read descriptorn");
11   Close(fd[0]);
12   sleep(6);
13   exit(0);
14  }
15  /* 4parent */
16  Close(fd[0]); /* для двустороннего канала */
17  sleep(3);
18  FD_ZERO(&wset);
19  FD_SET(fd[1], &wset);
20  n = select(fd[1] + 1, NULL, &wset, NULL, NULL);
21  printf("select returned %dn", n);
22  if (FD_ISSET(fd[1], &wset)) {
23   printf("fd[1] writablen");
24   Write(fd[1], "hello", 5);
25  }
26  exit(0);
27 }

Оглавление книги


Генерация: 0.074. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз