Document 7926957

Download Report

Transcript Document 7926957

Програмни канали
гл. ас. Моника Филипова
ФМИ, Катедра Изчислителни системи
Системно програмиране, М. Филипова
1
Съдържание






Видове програмни канали
Създаване на програмен канал
Писане в програмен канал
Четене от програмен канал
Затваряне на програмен канал
Създаване на FIFO файл
Системно програмиране, М. Филипова
2
Видове програмни канали


Неименовани програмни канали (unnamed pipe)
Именовани програмни канали (named pipe, FIFO file)
неименован
създаване
отваряне
четене/писане
затваряне
унищожаване
pipe
read и write
close
автоматично при close
Системно програмиране, М. Филипова
FIFO файл
mknod
open
read и write
close
unlink
3
Създаване на програмен канал
int pipe(int fd[2]);
Връща 0 при успех, -1 при грешка.
fd[0] - файлов дескриптор за четене от канала
fd[1] - файлов дескриптор за писане в канала
Системно програмиране, М. Филипова
4
Писане в програмен канал
ssize_t write(int fd, char *buf, size_t nbytes);
fd е файлов дескриптор за писане в програмен канал.
1.
2.
3.
Ако в канала има достатъчно място, то данните се записват
в края на файла, увеличава се размера на файла и се
събуждат всички процеси, чакащи да четат от канала.
Ако в канала няма достатъчно място за всичките данни и
nbytes е по-малък или равен на PIPE_BUFF (или
капацитета на канала), то ядрото блокира процеса. Когато
бъде събуден от друг процес, изпълняващ read, той
продължава както в случай 1.
Ако в канала няма достатъчно място за всичките данни, но
nbytes е по-голям от PIPE_BUFF (или капацитета на
канала), то в канала се записват толкова байта, колкото е
възможно и ядрото блокира процеса. Когато бъде събуден,
той продължава да пише.
Системно програмиране, М. Филипова
5
Четене от програмен канал
ssize_t read(int fd, char *buf, size_t nbytes);
fd е файлов дескриптор за четене от програмен канал.
1.
2.
Ако в канала има някакви данни, то започва четене от
началото на файла докато се удовлетвори искането на
процеса или докато има данни в канала. Намалява размера
на файла с прочетения брой байта и събужда всички
процеси, чакащи да пишат в канала.
Ако каналът е празен, ядрото блокира процеса. Когато бъде
събуден от друг процес, изпълняващ write, той
продължава както в случай 1.
Системно програмиране, М. Филипова
6
Затваряне на програмен канал
int close(int fd);
fd е файлов дескриптор за писане/четене в програмен канал.
1.
2.
3.
Ако при close се освободи последният файлов
дескриптор за писане в канала, то се събуждат всички
процеси, чакащи да четат от канала, като read връща 0.
Ако при close се освободи последният файлов
дескриптор за четене от канала, то се събуждат всички
процеси, чакащи да пишат в канала като им се изпраща
сигнал SIGPIPE.
Ако при close се освободи последният файлов
дескриптор за каквато и да е работа с канала, то
програмният канал се унищожава.
Системно програмиране, М. Филипова
7
Комуникация между два процеса с pipe
-
Процесът създава програмен канал с pipe
Процесът създава нов процес с fork
Бащата затваря файловия дескриптор за четене, а сина за
писане в програмния канал.
баща
син
read pd[0]
write pd[1]
read pd[0]
write pd[1]
ядро
pipe
син
баща
read pd[0]
write pd[1]
ядро
pipe
Системно програмиране, М. Филипова
8
Пример. Комуникация от баща към син с pipe
#include "ourhdr.h"
main(void)
{
int pd[2], n;
pid_t pid;
char buff[1024];
if (pipe(pd) < 0) {
/* parent creates a pipe */
perror("pipe error"); exit(1); }
if ((pid = fork()) < 0) {
perror("fork error"); exit(1); }
else if ( pid > 0) {
/* in parent process */
close(pd[0]);
write(pd[1], "Hello World\n", 12); }
else {
/* in child process */
close(pd[1]);
n = read(pd[0], buff, 1024);
write(1, buff, n); }
exit(0);
}
Системно програмиране, М. Филипова
9
Пример. Реализизация на конвейер "ls | wc -l"
Първи вариант

Процесът, в който работи програмата, създава син след
което чака завършването му.

Синът създава програмен канал и също създава син (внук на
процеса, в който работи програмата).

Процесът-син извиква програмата wc.

Процесът-внук извиква програмата ls.

Процесът-бащата чака завършването на процеса-син.
Втори вариант

Двата процеса за командите ls и wc са синове на процеса, в
който работи програмата.

Процесите за ls и wc са в една група с лидер ls.

Процесът-баща чака завършването на втория син (wc).
Системно програмиране, М. Филипова
10
#include "ourhdr.h"
main (void)
{
int pd[2], status;
pid_t pid;
if ( (pid = fork() ) < 0 )
err_sys_exit("fork error");
if ( pid == 0 ) {
/* in child */
if (pipe(pd) < 0)
err_sys_exit("pipe error");
if ( (pid = fork() ) < 0)
err_sys_exit("fork error");
else if ( pid == 0 ) {
/* in grandchild */
close(1);
dup(pd[1]);
close(pd[0]);
close(pd[1]);
execlp("ls", "ls", 0);
err_sys_exit("exec ls error");
}
Системно програмиране, М. Филипова
Първи вариант (1)
11
Първи вариант (2)
else {
/* in child */
close(0);
dup(pd[0]);
close(pd[0]);
close(pd[1]);
execlp("wc", "wc", "-l", 0);
err_sys_exit("exec wc error");
}
}
wait(&status);
/* in parent */
printf("Parent after end of pipe: status=%d\n", status);
exit(0);
}
Системно програмиране, М. Филипова
12
main (void)
Първи вариант (кратко решение)
{
int pd[2], status;
if ( fork() == 0 ) {
/* in child */
pipe(pd);
if ( fork() == 0) {
/* in grandchild */
close(1);
dup(pd[1]);
close(pd[0]);
close(pd[1]);
execlp("ls", "ls", 0);
perror("exec ls error"); exit(1);
} else {
/* in child */
close(0);
dup(pd[0]);
close(pd[0]);
close(pd[1]);
execlp("wc", "wc", "-l", 0);
perror("exec wc error"); exit(1);
}
}
wait(&status);
/* in parent */
}
Системно програмиране, М. Филипова
13
Втори вариант (1)
#include "ourhdr.h"
main (void)
{
int pd[2], status;
pid_t pid, pid2;
if ( pipe(pd) < 0 )
err_sys_exit("pipe error");
if ( (pid = fork() ) < 0 )
err_sys_exit("fork error for first child");
if ( pid == 0 ) {
/* in first child */
setpgrp();
printf("First : pid=%d, grp=%d, ppid=%d\n", getpid(), getpgrp(), getppid());
close(1);
dup(pd[1]);
close(pd[0]);
close(pd[1]);
execlp("ls", "ls", "-l", 0);
err_sys_exit("exec ls error");
}
Системно програмиране, М. Филипова
14
Втори вариант (2)
if ( (pid2 = fork() ) < 0 )
/* in parent */
err_sys_exit("fork error for second child");
if ( pid2 == 0 ) {
/* in second child */
setpgid(0, pid);
printf("Second: pid=%d, grp=%d, ppid=%d\n",getpid(),getpgrp(),getppid());
close(0);
dup(pd[0]);
close(pd[0]);
close(pd[1]);
execlp("wc", "wc", "-l", 0);
err_sys_exit("exec wc error");
}
close(pd[0]);
/* in parent */
close(pd[1]);
waitpid(pid2, &status, 0);
printf("Parent after end of pipe: status=%d\n", status);
exit(0);
}
Системно програмиране, М. Филипова
15
Създаване на FIFO файл
int mknod(const char *filename,
mode_t mode,
dev_t dev);
Връща 0 при успех, -1 при грешка.
int mkfifo(const char *filename,
mode_t mode);
Връща 0 при успех, -1 при грешка.
Пример
int mknod("fifoname", S_IFIFO|0600, 0);
int mkfifo("fifoname", 0600);
Системно програмиране, М. Филипова
16
Пример. Комуникация от баща към син с FIFO файл
#include "ourhdr.h"
#include <fcntl.h>
main(int argc, char *argv[])
{
int fdr, fdw, n;
pid_t pid;
char buff[MAXLINE];
if (argc < 2)
err_exit("usage: a.out fifo_name");
if (mknod(argv[1], S_IFIFO|0600, 0) < 0)
/* or mkfifo(argv[1], 0600) */
err_sys_exit("make fifo error");
if ((pid = fork()) < 0)
err_sys_exit("fork error");
else if (pid > 0) {
/* in parent */
if ((fdw = open(argv[1], O_WRONLY)) == -1)
err_sys_exit("open for write error");
write(fdw, "Hello World\nHello World\n", 24);
} else {
/* in child */
if ((fdr = open(argv[1], O_RDONLY)) == -1)
err_sys_exit("open for read error");
n = read(fdr, buff, 12);
write(1, buff, n);
}
exit(0);
}
Системно програмиране, М. Филипова
17
Резултат от изпълнение
$ a.out myfifo
Hello World
$ ls -l myfifo
prw------- 1 moni staff 0 Jul 21 10:22 myfifo
$ rm myfifo
Системно програмиране, М. Филипова
18
Пример. Производител-Потребител с FIFO файл
/* Producer with fifo file */
#include "ourhdr.h"
#include <fcntl.h>
main(int argc, char *argv[])
{
int fd, n;
if (argc < 2)
err_exit("usage: prod fifo_name");
if (mkfifo(argv[1], 0600) < 0)
err_sys_exit("prod: make fifo error");
if ((fd = open(argv[1], O_WRONLY)) < 0)
err_sys_exit("prod: open fifo error");
for (n=1; n<=100; n++) {
if ( write(fd, &n, sizeof(int)) < 0 )
err_sys_exit("write error");
}
exit(0);
}
Системно програмиране, М. Филипова
19
/* Consumer with fifo file */
#include "ourhdr.h"
#include <fcntl.h>
main(int argc, char *argv[])
{
int fd, n;
int buff;
if (argc < 2)
err_exit("usage: cons fifo_name");
if ( (fd = open(argv[1], O_RDONLY) ) < 0)
err_sys_exit("cons: open fifo error");
while ( ( n = read(fd, &buff, sizeof(int)) ) > 0 ) {
buff *= 2;
printf("Consumer: %d \n", buff);
}
if (unlink(argv[1]) == -1)
err_sys_exit("cons: unlink fifo error");
exit(0);
}
Системно програмиране, М. Филипова
20
Резултат от изпълнение
$ prod myfifo &
[1] 5808
$ cons myfifo
Consumer: 2
Consumer: 4
Consumer: 6
Consumer: 8
Consumer: 10
Consumer: 12
. . .
Consumer: 200
[1]+ Done
prod myfifo
$ ls -l myfifo
ls: myfifo: No such file or directory
Системно програмиране, М. Филипова
21