Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

END detection of pipe

François-Xavier
Beginner
1,013 Views
Dear forumers,

After researches about pipes on the forum, i didn't find the answer to this question:

I try to use named pipes between C++ (Writes in the pipe)and Fortran (reads in the pipe)executables.Data Transferworks great but I have a problem with the END statement of the FortranREAD command. In fact, the END is never reached under windows.

Small dummy example:

C++:
[cpp]#include 
#include


int main(){
std::cout << "server opened" <<:ENDL>
char data[500];
DWORD numWritten = 0 ;

HANDLE hPipe;
/*Will write to hPipe*/
LPTSTR lpszPipename = TEXT("\\.\pipe\mynamedpipe");

hPipe = CreateNamedPipe(lpszPipename,PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,256, 256, 100000, NULL);

std::cout << "pipe created" << std::endl;
if (hPipe != NULL) {
ConnectNamedPipe(hPipe, NULL);
std::cout << "client connected" << std::endl;


strcpy(data,"textern");
WriteFile(hPipe,data,strlen(data),&numWritten,NULL);
strcpy(data,"texte 10 15.8rn");
WriteFile(hPipe,data,strlen(data),&numWritten,NULL);
strcpy(data,"105rn");
WriteFile(hPipe,data,strlen(data),&numWritten,NULL);
strcpy(data,"avant derniere lignern");
WriteFile(hPipe,data,strlen(data),&numWritten,NULL);
strcpy(data,"derniere ligne");
WriteFile(hPipe,data,strlen(data),&numWritten,NULL);
//end of file
data[0] = EOF;
WriteFile(hPipe,data,1,&numWritten,NULL);

std::cout << "Prepare to flush" << std::endl;

FlushFileBuffers(hPipe);

std::cout << "information sent" << std::endl;

Sleep(1000000);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
}
else
std::cerr << "pipe not created" <<:ENDL>
std::cout << "server closed" <<:ENDL>}















[/cpp]
Fortran:

[cpp]program test

      IMPLICIT none
      
      CHARACTER LINE*120
      integer I,f, stat
      REAL*4 Y
      
      !lecture direct du fichier
      f=51
      open(f,file='\.pipemynamedpipe',status='UNKNOWN',
     *     form='FORMATTED',ACTION='READ')

      !ligne de texte de longueur inconnue
      read(f,'(A120)') LINE
      write(*,*) LINE
      
      !types et longeur connu
      read(f,'(A5,1X,I2,1X,F4.1)') LINE, I, Y
      write(*,*) LINE,' ',I,' ',Y
      
      !lecture texte jusqu' la fin de fichier
      do while (.TRUE.)
        read(f,'(A120)', END=100) LINE
        write(*,*) LINE
      end do
  100 continue
  
      close(f)    
      
      end program 
[/cpp]


In the example, the do while(.TRUE.) loop is problematic. Infact, the END=100 statement is never reached.

I have tested the principle under linux versionwithout any problem.

Do i miss something?

Thank you



0 Kudos
3 Replies
jimdempseyatthecove
Honored Contributor III
1,013 Views

Remove the Sleep in the C++ code following the FlushFileBuffers.
The DisconnectNamedPipe will cause the next read on the named pipe to fail. But your code does not issue the DisconnectNamedPipe until after the sleep (1000 seconds)

What I do not know, and will require experimentation on your part, is your Fortran side is performing a blocked read on the pipe handle. i.e. this read is already pending (i.e. will not be next read). The MSVC documentation does not state if this causes an EOF on pending ReadFiles, it only states error on next ReadFile. You may have to address that with some other means. Such as writing an end of file signature record or using a non-blocking read mode on the Fortran side and handling empty data (record of length=0)

Jim Dempsey




0 Kudos
François-Xavier
Beginner
1,013 Views

Remove the Sleep in the C++ code following the FlushFileBuffers.
The DisconnectNamedPipe will cause the next read on the named pipe to fail. But your code does not issue the DisconnectNamedPipe until after the sleep (1000 seconds)

What I do not know, and will require experimentation on your part, is your Fortran side is performing a blocked read on the pipe handle. i.e. this read is already pending (i.e. will not be next read). The MSVC documentation does not state if this causes an EOF on pending ReadFiles, it only states error on next ReadFile. You may have to address that with some other means. Such as writing an end of file signature record or using a non-blocking read mode on the Fortran side and handling empty data (record of length=0)

Jim Dempsey





Dear Jim,

I agree with your analysis, your are totally right with the Sleep.

However, concerning the EOF detection, you see in C++ side i have explicitly added an EOF in the pipe.

If i replace the do while loop in Fortran by:

[cpp]      do while (.NOT.EOF(f))
        read(f,'(A100)') LINE
      end do[/cpp]

The detection succeeds. I really wonder why the END statement in READ function does not reach to do the same job.

Sincerely yours,

F-Xavier

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,013 Views

Don't know.

On the C++ size, read and write to pipe sufficient number of lines to get into your do while(.not.EOF(f)) loop but with additional lines to read and write to pipe. Then break on the C++ side (assuming seperate app). Then run the Fortran side. The test will be to get the Fortran side to out pace the pipe fill side. This is to test for EOF(f) returning true for empty pipe as opposed to following DisconnectNamedPipe.

Should EOF(f) return true on empty pipe, then the code you have above is incorrect (when reader of pipe out paces writer of pipe). Do not assume writer will always run faster than reader because writer may get preempted by O/S.

I think, in abstract terms, a named pipe as structured in your applications,will behave like a shared sequential file. The writer can write any number of bytes into the file, and the reader can read up to the number of bytes written. When read is attempted past number of bytes written and EOF is returned. This EOF is not necessarily an indication that the writer has completed writing to the "file" (pipe). EOF(f) therefor should be an indication that either a) read out paced writes, or b) writer is in process of finishing off file. So, your code needs to handle both cases. Something like

123 continue
if(EOF(f)) then
INQUIRE(f, OPENED=I_OPENED)
if(.NOT. I_OPENED) GOTO PipeClosed
Sleep(10) ! assume outpaced writer
Goto 123
endif
read(f, ...

Jim Dempsey
0 Kudos
Reply