Las operaciones asíncronas con puertos de finalización de E / S devuelven 0 bytes transferidos

StackOverflow https://stackoverflow.com/questions/1602083

Pregunta

Las operaciones asíncronas con puertos de finalización de E / S devuelven 0 bytes transferidos, aunque las operaciones de E / S funcionan como se esperaba (mis búferes de lectura se llenan).

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
);

En el hilo de trabajo:

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

Ambas funciones devuelven 0 bytes en números, pero buffer se está llenando. ¿Es este el comportamiento esperado?

Gracias.

¿Fue útil?

Solución

Para que GetIoCompletionPort funcione correctamente, debe especificar un puntero que no sea nulo a un ULONG_PTR para que escriba el valor 'clave' en:

ULONG_PTR key;

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

Para utilizar GetOverlappedResult con éxito, creo que debe especificar un controlador de eventos en la estructura de OVERLAPPED (se recomienda encarecidamente en cualquier caso):

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

Llamar a los dos en sucesión tal como eras no logra mucho, ambos te hablan de las mismas cosas. Aunque si llama a ambos en sucesión, deberá cambiar el Evento para que se reinicie manualmente cambiando el tercer parámetro a CreateEvent a TRUE. Mi conjetura es que solo intentabas ver si podías conseguir que uno funcionara. Teniendo todo en cuenta, probablemente solo usaría GetQueuedCompletionStatus , y lo dejo así. Por supuesto, usualmente harás más que solo llamarlo una vez y renunciar. Normalmente lo llama en un bucle, procesando el búfer actual que ha leído, y luego llamando a ReadFile nuevamente para leer otro búfer de información, algo como esto:

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);
}

Al menos en una prueba rápida en mi máquina, esto mostraba el número de bytes leídos correctamente ( sizeof (buffer) hasta el último paquete, luego el tamaño restante del archivo).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top