Асинхронные операции с портами завершения ввода / вывода возвращают 0 байт - PullRequest
3 голосов
/ 21 октября 2009

Асинхронные операции с портами завершения ввода / вывода возвращают 0 байтов, хотя операции ввода / вывода работают как положено (мои буферы чтения заполняются).

BYTE buffer[1024] = {0};
OVERLAPPED o = {0};
HANDLE file = CreateFile(
    _T("hello.txt"),
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL
);
HANDLE completion_port = CreateIoCompletionPort(
    file,
    NULL,
    0,
    0
);
ReadFile(
    file,
    buffer,
    1024,
    NULL,
    &o
);

В рабочей теме:

DWORD numBytes = 0;
LPOVERLAPPED po;
GetQueuedCompletionStatus(
    completion_port,
    &numBytes,
    0,
    &po,
    INFINITE
);
GetOverlappedResult(file, &o, &numBytes, FALSE);

Обе функции возвращают 0 байтов в numBytes, но buffer заполняет. Это ожидаемое поведение?

Спасибо.

1 Ответ

3 голосов
/ 22 октября 2009

Для правильной работы GetIoCompletionPort необходимо указать ненулевой указатель на ULONG_PTR, чтобы записать значение ключа в:

ULONG_PTR key;

GetQueuedCompletionStatus(
    completion_port,
    &numBytes,
    &key,
    &po,
    INFINITE
);

Чтобы успешно использовать GetOverlappedResult, я считаю, что вам нужно указать дескриптор события в структуре OVERLAPPED (настоятельно рекомендуется в любом случае):

o.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

Называть двоих подряд такими, какими вы были, на самом деле мало что дает - они оба говорят вам об одних и тех же вещах. Хотя, если вы вызовете оба по очереди, вам нужно изменить Событие на ручной сброс, изменив третий параметр на CreateEvent на ИСТИНА. Я думаю, что вы просто пытались оба, чтобы увидеть, если вы могли бы получить один на работу. Учитывая все обстоятельства, я бы, вероятно, просто использовал GetQueuedCompletionStatus и оставил это на этом. Конечно, вы обычно делаете больше, чем звоните один раз и выходите. Вы обычно вызываете его в цикле, обрабатывая текущий прочитанный буфер, затем вызываете ReadFile снова, чтобы прочитать другой буфер информации, что-то вроде этого:

DWORD numBytes;
LPOVERLAPPED po;
while (GetQueuedCompletionStatus(completion_port, &numBytes, &key, &po, INFINITE)) {
    std::cout << "\rRead: " << numBytes; // just to show it's set correctly.
    process(buffer);
    po->offset += sizeof(buffer);
    ReadFile(file, buffer, sizeof(buffer), NULL, po);
}

По крайней мере, в быстром тесте на моей машине это показало количество прочитанных байт правильно (sizeof(buffer) до последнего пакета, затем оставшийся размер файла).

...