LINUX.ORG.RU

синхронизация pipe-ов через select?


0

0

Необходимо реализовать двустороннюю передачу данных между двумя процессами.
один на фортране (для меня это черный ящик, знаю тока протокол), другой на питоне и С++ (мой).
Фотрановская прога умеет по свистку открывать файл, читать из него данные или открывать файл, писать в него данные.
Всем этим бардаком рулит питон, C++ модуль подцеплен через swig.
Передач много, как правило Fortran->C++, C++-> Fortran по очередно.
И остро стоит вопрос с производительностью - основное время уходит как раз на передачи.


Попробовал сделать через именованные пайпы, один в одну сторону, другой в другую. Но вылезают жуткие праблы с синхронизацией. То С++ два раза достанет из папйпа одно и тоже. То фортран туда ничего не положит. Или положит и сидит ждет чего то... умные люди посоветовали попробовать select (со стороны С++, Fotran-новский код я менять не могу).

Сессия выглядит так - фотрановской программе грят (через управляющий пайп, его она прекрасно читает) сунуть данные в fifo1, потом вызывается С++-я функция которая fifo1 открывает и читает. Или наоборот, фортрану грят открыть файл fifo2 и прочитать из него данные, потом C++ ф-я открывает fifo2 и сует туда что нужно. В приципе хватило бы и одного fifo, но так совсем не работает - что для меня странно, C++-е программы я так женил (файлы открывал fstream-мом).

Кто то что то может откомментировать?

С selectom - пример из манула работает со стандартным вводом, но отказывается работать с пайпом открытым через open (данных не видит, скока их туда не суй).

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
using namespace std;

int main() {
long f=open("fifo",O_RDONLY);
fd_set rfds;
struct timeval tv;
int retval;
cout<<1<<endl;

/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(f, &rfds);

/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
cout<<2<<endl;

retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
cout<<3<<endl;

if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");

return 0;
}

Видимо я как то не так открываю файло? разные комбинации флагов положительного эффекта не дали.

anonymous

Ну по крайней мере одна ошибка в глаза бросается: первый аргумент select-а должен быть равен максимальному дескриптору в передаваемых fd_set'ах плюс 1, - а не количеству дескрипторов, как может показаться на первый взгляд. Если дескриптор один (f), то первым аргументом надо передавать f+1.

anonymous
()
Ответ на: комментарий от anonymous

Собственно, поэтому и работает со стандартным вводом: номер дескриптора stdin всегда равен 0, соответственно передаваемое число "1" по счастливому стечению обстоятельств - подходит для stdin.

anonymous
()
Ответ на: комментарий от anonymous

О! Спасибо большое, тест заработал:-)

А такой совсем наглый и дурацкий вопрос - мне бы файл открыть как fstream. Как бы у ftream-а узнать дескриптор для select-а (или дескриптор оформить под ftsream) ?

anonymous
()
Ответ на: комментарий от anonymous

Да, и все равно проблема остается - select соскакивает когда в пайпе появляется хоть что то (типа первая строка). А мне бы надо что бы селект соскакивал когда пайп полностью записан и закрыт с того конца - а то создается впечатление, что в некоторых случаях чтение происходит быстрее чем запись (то есть из пайпа С++ тупо достает последнее записанное значение ндцать раз подряд) - что для меня вообще то дико, вроде fifo по определению такого допускать не должно...

anonymous
()
Ответ на: комментарий от anonymous

У fstream'а узнать его handle не получится, это принципиально. Имея открытый дескриптор - можно создать istream или ostream. См., к примеру, boost::iostreams, там есть готовые обертки для этой цели.

anonymous
()
Ответ на: комментарий от anonymous

Select возвращает управление когда истекает таймаут или когда появляются данные для чтения. Сколько именно данных ты собираешься считать - select знать не может. Он (почти) гарантирует, что следующий вызов read будет неблокирующим, но при этом будет прочитано не обязательно столько байт, сколько ты попросишь в этом read (может быть прочитано меньше).

Такого понятия как "пайп полностью записан" в UNIX нет. Одно и то же из пайпа считаться не может, ищи ошибку у себя. При закрытии пайпа с другого конца, select вернет управление, если ты на нем ждал.

anonymous
()
Ответ на: комментарий от anonymous

О-хо-хонюшки... мне бы как раз нужно, что бы read был блокирующим (рано или поздно данные все равно появяться). Честно гря я думал что на пайпах read всегда блокирующий - иначе какой смысл? Руками что ли буферизацию и чинхронизацию городить???
Тогда бы хотелось знать, скока я реально прочитал...
Можно это как то реализовать на стреамах?

У меня используется конструция

fstream f(fname, ios::in);

double rho, ru, rv, E, Y;
for(int i=0;i<N;i++){
f>>rho>>ru>>rv>>E>>Y;
...
}

если read неблокирующий, то ес-но это не работает :-(

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.