Sincronização e entrada e saída sobrepostas

Você pode executar operações de E/S síncronas ou assíncronas (também chamadas de sobrepostas) em arquivos, pipes nomeados e dispositivos de comunicação serial. As funções WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipe e TransactNamedPipe podem ser executadas de forma síncrona ou assíncrona. As funções ReadFileEx e WriteFileEx só podem ser executadas de forma assíncrona.

Quando uma função é executada de forma síncrona, ela não retorna até que a operação seja concluída. Isso significa que a execução do thread de chamada pode ser bloqueada por um período indefinido enquanto aguarda a conclusão de uma operação demorada. As funções chamadas para a operação sobreposta podem retornar imediatamente, mesmo que a operação não tenha sido concluída. Isso permite que uma operação de E/S demorada seja executada em segundo plano enquanto o thread de chamada é livre para executar outras tarefas. Por exemplo, um único thread pode executar operações simultâneas de E/S em identificadores diferentes ou até mesmo operações simultâneas de leitura e gravação no mesmo identificador.

Para sincronizar sua execução com a conclusão da operação sobreposta, o thread de chamada usa a função GetOverlappedResult , a função GetOverlappedResultEx ou uma das funções de espera para determinar quando a operação sobreposta foi concluída. Você também pode usar a macro HasOverlappedIoCompleted para sondar a conclusão.

Para cancelar todas as operações de E/S assíncronas pendentes, use a função CancelIoEx e forneça uma estrutura OVERLAPPED que especifica a solicitação a ser cancelada. Use a função CancelIo para cancelar operações de E/S assíncronas pendentes emitidas pelo thread de chamada para o identificador de arquivo especificado.

As operações sobrepostas exigem um arquivo, pipe nomeado ou dispositivo de comunicação que foi criado com o sinalizador FILE_FLAG_OVERLAPPED . Quando um thread chama uma função (como a função ReadFile ) para executar uma operação sobreposta, o thread de chamada deve especificar um ponteiro para uma estrutura OVERLAPPED . (Se esse ponteiro for NULL, o valor retornado da função poderá indicar incorretamente que a operação foi concluída.) Todos os membros da estrutura OVERLAPPED devem ser inicializados como zero, a menos que um evento seja usado para sinalizar a conclusão de uma operação de E/S. Se um evento for usado, o membro hEvent da estrutura OVERLAPPED especificará um identificador para o objeto de evento alocado. O sistema define o estado do objeto de evento como não atribuído quando uma chamada para a função de E/S retorna antes que a operação seja concluída. O sistema define o estado do objeto de evento como sinalizado quando a operação for concluída. Um evento só será necessário se houver mais de uma operação de E/S pendente ao mesmo tempo. Se um evento não for usado, cada operação de E/S concluída sinalizará o arquivo, o pipe nomeado ou o dispositivo de comunicações.

Quando uma função é chamada para executar uma operação sobreposta, a operação pode ser concluída antes que a função retorne. Quando isso acontece, os resultados são tratados como se a operação tivesse sido executada de forma síncrona. No entanto, se a operação não tiver sido concluída, o valor retornado da função será FALSE e a função GetLastError retornará ERROR_IO_PENDING.

Um thread pode gerenciar operações sobrepostas por um dos dois métodos:

  • Use a função GetOverlappedResult ou GetOverlappedResultEx para aguardar a conclusão da operação sobreposta. Se GetOverlappedResultEx for usado, o thread de chamada poderá especificar um tempo limite para a operação sobreposta ou executar uma espera alertável.
  • Especifique um identificador para o objeto de evento de redefinição manual da estrutura OVERLAPPED em uma das funções de espera e, depois que a função de espera retornar, chame GetOverlappedResult ou GetOverlappedResultEx. A função retorna os resultados da operação sobreposta concluída e, para funções nas quais essas informações são apropriadas, ela relata o número real de bytes que foram transferidos.

Ao executar várias operações sobrepostas simultâneas em um único thread, o thread de chamada deve especificar uma estrutura OVERLAPPED para cada operação. Cada estrutura OVERLAPPED deve especificar um identificador para um objeto de evento de redefinição manual diferente. Para aguardar a conclusão de qualquer uma das operações sobrepostas, o thread especifica todos os identificadores de evento de redefinição manual como critérios de espera em uma das funções de espera de vários objetos. O valor retornado da função de espera de vários objetos indica qual objeto de evento de redefinição manual foi sinalizado, de modo que o thread pode determinar qual operação sobreposta fez com que a operação de espera fosse concluída.

É mais seguro usar um objeto de evento separado para cada operação sobreposta, em vez de especificar nenhum objeto de evento ou reutilizar o mesmo objeto de evento para várias operações. Se nenhum objeto de evento for especificado na estrutura OVERLAPPED , o sistema sinalizará o estado do arquivo, pipe nomeado ou dispositivo de comunicação quando a operação sobreposta for concluída. Portanto, você pode especificar esses identificadores como objetos de sincronização em uma função de espera, embora seu uso para essa finalidade possa ser difícil de gerenciar porque, ao executar operações sobrepostas simultâneas no mesmo arquivo, pipe nomeado ou dispositivo de comunicações, não há como saber qual operação fez com que o estado do objeto fosse sinalizado.

Um thread não deve reutilizar um evento com a suposição de que o evento será sinalizado apenas pela operação sobreposta desse thread. Um evento é sinalizado no mesmo thread que a operação sobreposta que está sendo concluída. Usar o mesmo evento em vários threads pode levar a uma condição de corrida na qual o evento é sinalizado corretamente para o thread cuja operação é concluída primeiro e prematuramente para outros threads usando esse evento. Em seguida, quando a próxima operação sobreposta for concluída, o evento será sinalizado novamente para todos os threads que usam esse evento e assim por diante até que todas as operações sobrepostas sejam concluídas.

Para obter exemplos que ilustram o uso de operações sobrepostas, rotinas de conclusão e a função GetOverlappedResult , consulte Usando pipes.

Windows Vista, Windows Server 2003 e Windows XP:

Tenha cuidado ao reutilizar estruturas OVERLAPPED . Se as estruturas OVERLAPPED forem reutilizados em vários threads e GetOverlappedResult for chamado com o parâmetro bWait definido como TRUE, o thread de chamada deverá garantir que o evento associado seja sinalizado antes de reutilizar a estrutura. Isso pode ser feito usando a função WaitForSingleObject depois de chamar GetOverlappedResult para forçar o thread a aguardar até que a operação seja concluída. Observe que o objeto de evento deve ser um objeto de evento de redefinição manual. Se um objeto de evento autoreset for usado, chamar GetOverlappedResult com o parâmetro bWait definido como TRUE fará com que a função seja bloqueada indefinidamente. Esse comportamento mudou a partir do Windows 7 e do Windows Server 2008 R2 para aplicativos que especificam o Windows 7 como o sistema operacional com suporte no manifesto do aplicativo. Para obter mais informações, consulte Manifestos do aplicativo.

Conceitos de E/S