3
  hPipe = CreateNamedPipe( 
     lpszPipename,             // pipe name 
     PIPE_ACCESS_DUPLEX,       // read/write access 
     PIPE_TYPE_MESSAGE |       // message type pipe 
     PIPE_READMODE_MESSAGE |   // message-read mode 
     PIPE_WAIT,                // blocking mode 
     PIPE_UNLIMITED_INSTANCES, // max. instances  
     100,                  // output buffer size 
     100,                  // input buffer size 
     0,                        // client time-out 
     NULL);                    // default security attribute 

  DWORD totalBytesAvailable; 
  PeekNamedPipe( 
    hPipe ,                // __in       HANDLE hNamedPipe, 
    NULL,                  // __out_opt  LPVOID lpBuffer, 
    0,                     // __in       DWORD nBufferSize, 
    NULL,                  // __out_opt  LPDWORD lpBytesRead, 
    &totalBytesAvailable,  // __out_opt  LPDWORD lpTotalBytesAvail, 
    NULL                   // __out_opt  LPDWORD lpBytesLeftThisMessage 
  ); 
    if(totalBytesAvailable allows)
    WriteFile( tmp_pipe, pBuffer, BufferLen, &dwWritten, NULL );

As you see I used PeekNamedPipe to get available space,but it turns out that totalBytesAvailable is always 0,how to do it properly?

Alan
  • 5,029
  • 5
  • 32
  • 37
  • @Frerich - of course, my time spent at SO. It know it has no value to Alan, but I certainly care. Being lazy marking answers is just dumb, considering its price. – Hans Passant Sep 15 '10 at 13:43
  • I guess you're writing to `hPipe`, not some unknown `tmp_pipe`? – pascal Sep 21 '10 at 01:47

6 Answers6

4

IMHO, this approach of checking the free space before doing the actual write is flawed.

It might happen that by the time the actual write gets executed, some other process running in parallel fills out the last bits of free disk space thus causing your WriteFile to fail.

I would rely only on what WriteFile returns.

tudor
  • 66
  • 2
  • I can't rely on `WriteFile`,it'll hang! And there's no need to worry about the multi-thread case in my case. – Alan Sep 16 '10 at 14:42
  • No this is the correct way to do it. Other processes share the disk, you can't guarantee that they won't fill empty space you presumed to claim either. The call won't hang if an error occurs (such as no disk space). You should get something like `GetLastError() == ERROR_DISK_FULL` after the call. – Matt Joiner Sep 18 '10 at 15:15
  • The call will hang if there's no space left for `WriteFile`,which I'm to avoid. – wamp Sep 20 '10 at 08:15
2

The values returned in the lpTotalBytesAvail parameter is the number of bytes that may be read from a pipe, not written to the pipe. Give you the information to allocate a buffer reading data from a pipe.

The correct approach to handling errors when writing to a pipe - or any NT Krenel handle -- is to simply execute the call to WriteFile() and handle any errors returned.

The check then write pattern is not effective and will yield bugs that * Never happen in your tests * Happen sometimes in the field * ... and are thus very difficult to diagnose and debug * most importantly, such bugs will annoy your users.

The reason is that the state of the destination can change between the check and the actual write. This means that your code that calls WriteFile() must check for errors anyway. This means that checking for a pre-condition before calling WriteFile()is simply extra code that provides no value.

The reason this pattern isn't effective is that Windows (and all other operating systems - this isn't just a windows thing) - cannot treat the "check" and the 'write" as atomic operations. The underlying OS is fully asynchronous and lots can happen between the calls.

So, your code will be simpler and more reliabile if you simple call WriteFile() and do a good job of error handling.

-Foredecker

Foredecker
  • 7,395
  • 4
  • 29
  • 30
1

You can't determine the free space in the way you are doing it.

While this question is about pipes, it's possible people may come across it looking for general information on discovering available disk space, and if the pipe is ultimately a file, this might still be useful:

The Knowledge Base article "Understanding and Using GetDiskFreeSpace and GetDiskFreeSpaceEx" gives info on the relevant Win32 APIs for determine free disk space, or go straight to the API documentation here:

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • I realise that, will edit to clarify. The way the question is phrased is likely to lead people who are searching for a way to find free disk space though, so I thought it would still be useful. – Paul Dixon Sep 14 '10 at 07:35
1

Set PIPE_NOWAIT instead of PIPE_WAIT. Then WriteFile will return immediately if there's not enough room in the pipe.
And 100 seems rather small for the I/O buffer sizes! What is your pipe for?

TonyK
  • 16,761
  • 4
  • 37
  • 72
  • That's what I said, isn't it? – TonyK Sep 21 '10 at 11:19
  • Then you won't know whether `WriteFile` succeeds or not. – Alan Sep 21 '10 at 15:09
  • If WriteFile doesn't succeed, it returns with an error code, instead of hanging. Which is what the OP wanted. (There seems to be no actual file involved here, if I understand the question.) – TonyK Sep 21 '10 at 15:22
1

The comments regarding the fragility of check then write are correct.

The suggestion of PIPE_NOWAIT is not recommended by Microsoft.

Use overlapped I/O. Then WriteFile() will always return immediately, and will return FALSE with ERROR_IO_PENDING if the data didn't write immediately into the pipe. In that case you call CancelIo() to cancel the attempted WriteFile(). Bear in mind that after calling CancelIo() you must then call GetOverlappedResult() because the overlapped WriteFile() still needs to complete - even though it is going to fail and if you free the OVERLAPPED structure before it does you will have stack corruption.

By the way, you should accept an answer on this question. It's more than a year since you asked it!

Ian Goldby
  • 5,609
  • 1
  • 45
  • 81
0

Create a thread to handle to writing to the pipe, so that it's not a problem having the writer hang, waiting for the client to empty the pipe?

pascal
  • 3,287
  • 1
  • 17
  • 35