Чтение онлайн

ЖАНРЫ

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

Стивенс Уильям Ричард

Шрифт:

В листинге А.1 приведен текст первой половины программы bw_pipe, измеряющей полосу пропускания канала.

Листинг А.1. Функция main, измеряющая полосу пропускания канала

//bench/bw_pipe.c

1 #include "unpipc.h"

2 void reader(int, int, int);

3 void writer(int, int);

4 void *buf;

5 int totalnbytes, xfersize;

6 int

7 main(int argc, char **argv)

8 {

9 int i, nLoop, contpipe[2], datapipe[2];

10 pid_t childpid;

11 if (argc != 4)

12 err_quit("usage: bw_pipe <#loops> <#mbytes> <#bytes/write>");

13 nloop = atoi(argv[1]);

14 totalnbytes = atoi(argv[2]) * 1024 * 1024;

15 xfersize = atoi(argv[3]);

16 buf = Valloc(xfersize);

17 Touch(buf, xfersize);

18 Pipe(contpipe);

19 Pipe(datapipe);

20 if ((childpid = Fork) == 0) {

21 writer(contpipe[0], datapipe[1]); /* child */

22 exit(0);

23 }

24 /* 4parent */

25 Start_time;

26 for (i = 0; i < nloop; i++)

27 reader(contpipe[1], datapipe[0], totalnbytes);

28 printf("bandwidth: %.3f MB/sec\n",

29 totalnbytes / Stop_time * nloop);

30 kill(childpid, SIGTERM);

31 exit(0);

32 }

Аргументы
командной строки

11-15 Аргументы командной строки задают количество повторов (обычно 5), количество передаваемых мегабайтов (если указать 10, будет передано 10×1024×1024 байт) и количество байтов для каждой операции read и write (которое может принимать значения от 1024 до 65536 в наших измерениях).

Выделение буфера и помещение начального значения

16-17 Вызов valloc аналогичен malloc, но выделяемая память начинается с границы страницы памяти. Функция touch (листинг А.3) помещает 1 байт данных в каждую страницу буфера, заставляя ядро считать в память все страницы данного буфера. Мы всегда выполняем это перед проведением измерений.

ПРИМЕЧАНИЕ

Функция valloc не входит в стандарт Posix.1 и названа устаревшей в Unix 98. Она требовалась в ранних версиях спецификаций Х/Open, но уже не является необходимой. Обертка Valloc вызывает функцию malloc, если valloc недоступна.

Создание двух каналов

18-19 Создаются два канала: contpipe[0] и contpipe[1] используются для синхронизации процессов перед началом передачи, a datapipe[0] и datapipe[1] используются для передачи самих данных.

Вызов fork

20-31 Создается дочерний процесс, вызывающий функцию writer, а родительский процесс в это время вызывает функцию reader. Функция reader вызывается nlоор раз. Функция start_time вызывается непосредственно перед началом цикла, a stop_time — сразу после его окончания. Эти функции даны в листинге А.З. Полоса пропускания

представляет собой количество байтов, переданных за все проходы цикла, поделенное на время, затраченное на передачу (stop_time возвращает количество микросекунд, прошедшее с момент запуска start_time). Затем дочерний процесс завершается сигналом SIGTERM и программа завершает свою работу. Вторая половина программы приведена в листинге А.2. Она состоит из функций reader и writer.

Листинг А.2. Функции reader и writer

//bench/bw_pipe.cvoid

33 void

34 writer(int contfd, int datafd)

35 {

36 int ntowrite;

37 for(;;) {

38 Read(contfd, &ntowrite, sizeof(ntowrite));

39 while (ntowrite > 0) {

40 Write(datafd, buf, xfersize);

41 ntowrite –= xfersize;

42 }

43 }

44 }

45 void

46 reader(int contfd, int datafd, int nbytes)

47 {

48 ssize_t n;

49 Write(contfd, &nbytes, sizeof(nbytes));

50 while ((nbytes > 0) &&

51 ((n = Read(datafd, buf, xfersize)) > 0)) {

52 nbytes –= n;

53 }

54 }

Функция writer

33-44 Функция writer представляет собой бесконечный цикл, вызываемый дочерним процессом. Он ожидает сообщения родительского процесса о готовности к приему данных, считывая целое число из управляющего канала. Это целое число определяет количество байтов, которое будет записано в канал данных. При получении этого числа дочерний процесс записывает данные в канал, отправляя их родителю. За один вызов write записывается xfersize байтов.

Функция reader

45-54 Эта функция вызывается родительским процессом в цикле. Каждый раз при вызове функции в управляющий канал записывается целое число, указывающее дочернему процессу на необходимость помещения соответствующего количества данных в канал данных. Затем функция вызывает read в цикле до тех пор, пока не будут приняты все данные.

Текст функций start_time, stop_time и touch приведен в листинге А.З.

Листинг А.З. Функции start_sime, stop_time и touch

//lib/timing.с

1 #include "unpipc.h"

2 static struct timeval tv_start, tv_stop;

3 int

4 start_time(void)

5 {

6 return(gettimeofday(&tv_start, NULL));

7 }

8 double

9 stop_time(void)

10 {

11 double clockus;

12 if (gettimeofday(&tv_stop, NULL) == –1)

Поделиться с друзьями: