Чтобы связать анонимные каналы с объектами классов ifstream и ofstream, мы использовали нестандартное связывание с файловым дескриптором. Нестандартность ситуации вытекает из того, что «брак» между файловыми дескрипторами и iostreams-объектами пока не «освящен» стандартом ISO С++. Поэтому безопаснее использовать FIFO-структуры. К FIFO-файлу специального типа можно получить доступ с помощью имени в файловой системе, в которой «официально» поддерживается связывание с объектами С++-классов ifstream и ofstream. Поэтому точно так же, как мы упрощали межпроцессное взаимодействие (IPC) с помощью iostream-классов и анонимного канала, мы упрощаем доступ к FIFO-структуре. FIFO-структура, основные функции которой совпадают с функциями анонимного канала, позволяет распространить возможности взаимодействия на классы, не связанные никакими родственными отношениями. Однако каждая программа — участник взаимодействия должна при этом «знать» имена FIFO-структур. Это требование, казалось бы, напоминает ограничение, с котороым мы встречались при использовании файловых дескрипторов. Однако FIFO — это все же «шаг вперед». Во-первых, при открытии анонимного канала только система определяет, какие файловые дескрипторы доступны в данный момент. Это означает, что программист не в состоянии полностью контролировать ситуацию. Во-вторых, существует ограничение на количество файловых дескрипторов, котороми располагает система. В-третьих, поскольку FIFO-структурам имена присваиваются пользователем, то количество таких имен не ограничивается. Файловые дескрипторы должны принадлежать файлам, открытым ранее (и причем успешно), а FIFO-имена — это всего лишь имена. FIFO-имя определяется пользователем, а файловые дескрипторы— системой. Имена файлов связываются с объектами классов ifstream, fstream и ofstream с помощью либо конструктора класса либо метода open(). В программе 11.3.1 для связывания объектов классов ofstream и ifstream с FIFO-структурой используется конструктор.
// Программа 11.3.1
14 using namespace std;
15
16 const int FMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
17
18 int main(int argc, char *argv[])
19 {
20
21 int Pid,Status,Size;
22 double Value;
25 mkfifo("/tmp/channel.l»,FMode) ;
26 mkfifo (" / tmp/channel. 2», FMode) ;
28 vector<double> X(100,13.0);
29 vector<double> Y;
30 ofstream OPipe("/tmp/channel.l»,ios::app);
31 ifstream IPipe("/tmp/channel.2»);
32 OPipe << X.size() « endl;
33 ostream_iterator<double> Optr(OPipe,"n»);
34 copy(X.begin(),X.end(),Optr);
35 OPipe « flush;
36 IPipe » Size;
37 for (int N = 0;N < Size; N++)
38 {
39 IPipe » Value;
40 Y.push_back(Value);
41 }
42
43 IPipe.close();
44 OPipe.close();
45 unlink("/tmp/channel.1»);
46 unlink("/tmp/channel.2»);
47 cout « accumulate(Y.begin(),Y.end(),-13.0) « endl;
48
49 return(0);
50 }
В программе 11.3.1 используется две FIFO-структуры. Вспомните, что FIFO-структуры являются однонаправленными компонентами. Поэтому, если процессы должны обмениваться данными, то необходимо использовать по крайней мере две FIFO-структуры. В программе 11.3.1 они называются channel.1 и channel.2. Обратите внимание на установку флагов полномочий для FIFO-структур (строка 16). Эти полномочия означают, что владелец FIFO-структуры имеет право доступа для чтения и записи, а все остальные — право доступа только для чтения. При выполнении строки 30 FIFO-структура channel.1 будет открыта только для вывода данных. Тот же результат можно было бы получить следующим образом : OPipe. open ("/tmp/channel.1», ios::app);
Используемые здесь параметры алгоритма open () означают, что FIFO-структура будет открыта в режиме дозаписи. В программе 11.3.1 алгоритм copy () используется для вставки объектов в объект OPipe типа fstream и косвенно в FIFO-структуру. Мы могли бы также использовать здесь объект типа
fstream:fstreamOPipe("/tmp/channel.l», ios::out | ios::app);
В этом случае взаимодействие процессов было бы ограничено выводом данных только в режиме дозаписи. Если бы мы не использовали флаг ios: :app , попытка объекта типа ofstream создать FIFO-сгруктуру (см. строку 30) была бы неудачной.
К сожалению, такой вариант работать не будет. Создание FIFO-структур находится в компетенции функции mkfifo(). В строках 45 и 46 программы 11.3.1 FIFO-структуры удаляются из файловой систе м ы. С этого м о м ента любые процессы, в которых открыты FIFO-структуры, еще в состоянии получить к ним доступ. Однако их имен больше не существует. Поэтому такие процессы не смогут использовать алгоритм open() или создать новые объекты типа ofstream или ifstream на основе и м ени, которое было «отсоединено». В строках 32-34, объекты типа ostream_ iterator и ofstream используются для вставки эле м ентов в FIFO-структуру. Обратите вни м ание на то, что програ мм а 11.3.1 не образует никаких ветвлений и не создает сыновних процессов. Программа 11.3.1 зависит от другой програ мм ы, которая должна считывать инфор м ацию из FIFO-структуры channel . 1 или записывать инфор м ацию в FIFO-структуру channel . 2 . Если такая программа не будет работать одновременно с программой 11.3.1, последняя останется заблокированной. Детали реализации приведены в разделе «Профиль программы 11.3.1».
Профиль программы 11.3.1
Имя программы program11-3a.cc
Описание Для пересылки контейнерного объекта через FIFO-структуру используются объекты ТИпа ostream_iterator и ofstream. Для извлечения информации из FIFO-структуры применяется объект типа ifstream.
Требуемые заголовки
<unistd.h>, <iomanip>, <algorithm>, <fstream.h>,<vector>,<iterator> <strstream.h>, <stdlib.h>, <sys/wait.h>, <sys/types.h>, <sys/stat.h> <fcntl.h>, <numeric>.
Инструкции по компиляции и компоновке программ
с++ -о program11-3a program113a.сс
Среда для тестирования
SuSE Linux 7.1, gcc 2.95.2, Solaris 8, Sun Workshop 6.
Инструкции по выполнению
./program11-3a & program11-3b
Примечания
Сначала запускается программа 11.3.1. Программа11.3.2 содержит инструкцию sleep, которая восполняет собой отсутствие реальной синхронизации.
Программа 11.3.2 считывает данные из FIFO-структуры channel. 1 и записывает информацию в FIFO-структуру channel. 2.
// Программа 11.3.2. Считывание данных из FIFO-структуры
// channel.l и запись информации в
// FIFO-структурУ channel.2
10 using namespace std; 11
12 class multiplier{
13 double X,-
14 public:
15 multiplier(double Value) { X = Value;}
16 double &operator()(double Y) { X = (X * Y);return(X);}
17 }; 18
19
20 int main(int argc,char *argv[])
21 { 22
23 double Size;
24 double Data;
25 vector<double> X;
26 multiplier R(1.5);
27 sleep(15);
28 fstream IPipe("/tmp/channel.1»);
29 ofstream OPipe("/tmp/channel.2»,ios::app);
30 if(IPipe.is_open()){
31 IPipe » Size;
32 }
33 else{
34 exit(l);
35 }
36 cout « «Количество элементов " << Size << endl;
37 for(int N = 0;N < Size;N++)
38 {
39 IPipe » Data;
40 X.push_back(Data);
41 }
42 OPipe « X.size() « endl;
43 ostream_iterator<double> Optr(OPipe,"n»);
44 transform(X.begin(),X.end(),Optr,R);
45 OPipe << flush;
46 OPipe.close();
47 IPipe.close();
48 return(0); 49