c - Datatab i Windows-pipelæsningsfunktion, når der bruges timeout

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg bruger asynkront IO i c på Windows til at læse og skrive et IPC-rør. Hvis jeg bruger en endeløs timeout til læsning virker alt som forventet. Jeg har allerede reduceret koden til for dette indlæg. I den rigtige applikation er der operationer mellem læsning og skriver. Har nogen en ide om, hvad der forårsager datatab. Funktionen fungerer kun, hvis timeout er INFINITY. Hvis jeg ikke bruger CancelIo () i tilfælde af timeout virker det slet ikke.


Jeg åbner klientkøen med cmd:


comm->pipeH = CreateFile(comm->pipeName, GENERIC\_READ | GENERIC\_WRITE, 0, NULL, OPEN\_EXISTING, FILE\_FLAG\_OVERLAPPED, NULL);


Og server køen:


comm->pipeH = CreateNamedPipe(comm->pipeName, PIPE\_ACCESS\_DUPLEX | FILE\_FLAG\_OVERLAPPED, PIPE\_TYPE\_BYTE | PIPE\_READMODE\_BYTE | PIPE\_WAIT,
                                  instances, PIPE\_BUF\_SIZE, PIPE\_BUF\_SIZE, 0, NULL);   


Dette er læsefunktionen


uint32\_t readBytesPipeCommChannel(PipeCommChannelData* comm, uint32\_t* amount, uint32\_t timeout)
{
    OVERLAPPED osRead;
    memset(&osRead, 0, sizeof(osRead));  
    osRead.hEvent = comm->readAsyncIOEvent;
    *amount = 0;
    DWORD readBytes = 0;
    int err = 0; 
    if(!ReadFile(comm->pipeH, comm->receiveBuffer, sizeof(comm->receiveBuffer), NULL, &osRead))
    {       
        err = GetLastError();
        if (err == ERROR\_IO\_PENDING)
        {
            int waitRes = WaitForSingleObject(osRead.hEvent, timeout);
            if(waitRes == WAIT\_TIMEOUT)
            {
                CancelIo(comm->pipeH);
                return PIPE\_IO\_TIMEOUT;
            }
            else if(waitRes != WAIT\_OBJECT\_0)
            {
                CancelIo(comm->pipeH);
                return PIPE\_READ\_ERR;
            }
        }
        else if(err != ERROR\_BROKEN\_PIPE)
        {
            return PIPE\_READ\_ERR;
        }
    }

    err = GetLastError();      
    if(err == ERROR\_BROKEN\_PIPE)
        return PIPE\_BROKEN\_ERR;
    else
        GetOverlappedResult(comm->pipeH, &osRead, &readBytes, TRUE);
    *amount = readBytes;
    return PIPE\_OK;
}


Dette er min forenklede overførselsfunktion.


ThorPipeCommunicationError sendBytesPipeCommChannel(PipeCommChannelData* comm, const uint8\_t* bytes, uint32\_t amount)
{
    DWORD bytesWritten = 0;
    OVERLAPPED osWrite;
    memset(&osWrite, 0, sizeof(osWrite));  
    osWrite.hEvent = comm->writeAsyncIOEvent;

    for(uint32\_t curPos = 0; curPos < amount; curPos += bytesWritten)
    {
        if(!WriteFile(comm->pipeH, &bytes[curPos], (amount - curPos), &bytesWritten, &osWrite))
        {
            if (GetLastError() != ERROR\_IO\_PENDING)
            {
                return PIPE\_WRITE\_ERR; 
            }
            if(WaitForSingleObject(osWrite.hEvent, INFINITE) != WAIT\_OBJECT\_0)
                CancelIo(comm->pipeH);
        }
    }
    return THOR\_PIPE\_OK;
}

Bedste reference