Как проверить, достаточно ли места перед записью в c в Windows? - PullRequest
3 голосов
/ 11 сентября 2010
  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 );

Как видите, я использовал PeekNamedPipe, чтобы получить доступное пространство, но оказывается, что totalBytesAvailable всегда 0, как это сделать правильно?

Ответы [ 6 ]

4 голосов
/ 15 сентября 2010

ИМХО, этот подход проверки свободного пространства перед выполнением реальной записи некорректен.

Может случиться, что к тому времени, когда фактическая запись будет выполнена, какой-то другой процесс, выполняющийся параллельно, заполняет последние битысвободного дискового пространства, что приводит к сбою WriteFile.

Я бы полагался только на то, что возвращает WriteFile.

2 голосов
/ 19 сентября 2010

Значения, возвращаемые в параметре lpTotalBytesAvail , представляют собой число байтов, которое может быть прочитано из канала, а не записано в канал.Предоставить вам информацию для выделения буфера для чтения данных из канала.

Правильный подход к обработке ошибок при записи в канал - или любой дескриптор NT Krenel - это просто выполнить вызов WriteFile() и обработайте все возвращенные ошибки.

Шаблон проверки и записи не эффективен и приведет к ошибкам, которые * никогда не встречаются в ваших тестах * Иногда случаются в поле * ... и, следовательно, очень трудно диагностировать и отлаживать * самое главное, такие ошибкибудет раздражать ваших пользователей.

Причина в том, что состояние пункта назначения может меняться между проверкой и фактической записью.Это означает, что ваш код, который вызывает WriteFile (), должен в любом случае проверять наличие ошибок.Это означает, что проверка предварительного условия перед вызовом WriteFile () - это просто дополнительный код, который не предоставляет значения.

Причина, по которой этот шаблон неэффективен, заключается в том, что Windows (и все другие операционные системы - это не просто Windows) - не могут рассматривать «проверку» и «запись» как атомарные операции.Базовая ОС полностью асинхронна, и между вызовами может произойти много.

Таким образом, ваш код будет проще и более надежным, если вы просто вызовете WriteFile () и хорошо справитесь с обработкой ошибок..

-Foredecker

1 голос
/ 20 сентября 2010

Установите PIPE_NOWAIT вместо PIPE_WAIT.Тогда WriteFile немедленно вернется, если в канале недостаточно места.
И 100 кажется довольно маленьким для размеров буфера ввода / вывода!Для чего ваша труба?

1 голос
/ 14 сентября 2010

Вы не можете определить свободное место так, как вы это делаете.

Хотя этот вопрос касается каналов, возможно, что люди могут встретить его, ища общую информацию об обнаружении доступного дискового пространства, и, если канал в конечном итоге является файлом, это все равно может быть полезно:

В статье базы знаний «Понимание и использование GetDiskFreeSpace и GetDiskFreeSpaceEx» приведены сведения о соответствующих API-интерфейсах Win32 для определения свободного места на диске или перейдите прямо к документации API здесь:

0 голосов
/ 10 октября 2011

Комментарии относительно хрупкости проверки и записи правильны.

Предложение PIPE_NOWAIT не рекомендуется Microsoft.

Используйте перекрывающиеся операции ввода-вывода.Тогда WriteFile () всегда будет возвращаться немедленно и будет возвращать FALSE с ERROR_IO_PENDING, если данные не записывались немедленно в канал.В этом случае вы вызываете метод CancelIo (), чтобы отменить попытку WriteFile ().Имейте в виду, что после вызова CancelIo () вы должны затем вызвать GetOverlappedResult (), потому что перекрывающийся WriteFile () все еще должен завершиться - даже если он потерпит неудачу и если вы освободите структуру OVERLAPPED, прежде чем это произойдет, у вас будет повреждение стека.

Кстати, вы должны принять ответ на этот вопрос.Прошло уже больше года с тех пор, как ты спросил об этом!

0 голосов
/ 21 сентября 2010

Создать поток для обработки записи в канал, чтобы не было проблем с зависанием модуля записи в ожидании, когда клиент опустошит канал?

...