Partilhar via


E/S síncrona e assíncrona

Consulte também aplicativos de exemplo relacionados a E/S.

Existem dois tipos de sincronização de entrada/saída (E/S): E/S síncrona e E/S assíncrona. E/S assíncrona também é conhecida como E/S sobreposta.

Em arquivo síncrono, um thread inicia uma operação de E/S e entra imediatamente em um estado de espera até que a solicitação de E/S seja concluída. Um thread executando arquivo assíncrono de E/S envia uma solicitação de E/S para o kernel chamando uma função apropriada. Se a solicitação for aceita pelo kernel, o thread de chamada continuará processando outro trabalho até que o kernel sinalize ao thread que a operação de E/S está concluída. Em seguida, ele interrompe seu trabalho atual e processa os dados da operação de E/S conforme necessário.

Os dois tipos de sincronização são ilustrados na figura a seguir.

Uma captura de tela de um diagrama ilustrando E/S síncronas e assíncronas.

Em situações em que se espera que uma solicitação de E/S leve uma grande quantidade de tempo, como uma atualização ou backup de um banco de dados grande ou um link de comunicação lento, a E/S assíncrona geralmente é uma boa maneira de otimizar a eficiência do processamento. No entanto, para operações de E/S relativamente rápidas, a sobrecarga de processamento de solicitações de E/S do kernel e sinais do kernel pode tornar a E/S assíncrona menos benéfica, particularmente se muitas operações de E/S rápidas precisarem ser feitas. Nesse caso, a E/S síncrona seria melhor. Os mecanismos e detalhes de implementação de como realizar essas tarefas variam dependendo do tipo de identificador de dispositivo que é usado e as necessidades particulares do aplicativo. Em outras palavras, geralmente há várias maneiras de resolver o problema.

Considerações de E/S síncronas e assíncronas

Se um arquivo ou dispositivo for aberto para E/S síncrona (ou seja, FILE_FLAG_OVERLAPPED não for especificado), chamadas subsequentes para funções como WriteFile poderão bloquear a execução do thread de chamada até que ocorra um dos seguintes eventos:

  • A operação de E/S é concluída (neste exemplo, uma gravação de dados).
  • Ocorre um erro de E/S. (Por exemplo, o tubo é fechado da outra extremidade.)
  • Foi cometido um erro na própria chamada (por exemplo, um ou mais parâmetros não são válidos).
  • Outro thread no processo chama a função CancelSynchronousIo usando o handle do thread bloqueado, que encerra a E/S desse thread, causando falha na operação de E/S.
  • O thread bloqueado é encerrado pelo sistema; por exemplo, o processo em si é encerrado ou outro thread chama a função TerminateThread usando o identificador do thread bloqueado. (Isso geralmente é considerado um último recurso e não é um bom design de aplicativo.)

Em alguns casos, esse atraso pode ser inaceitável para o design e a finalidade do aplicativo, portanto, os designers de aplicativos devem considerar o uso de E/S assíncronas com objetos de sincronização de thread apropriados, como portas de conclusão de E/S . Para obter mais informações sobre a sincronização de threads, consulte Sobre a sincronização.

Um processo abre um ficheiro para E/S assíncrona na sua chamada para CreateFile, especificando o sinalizador FILE_FLAG_OVERLAPPED no parâmetro dwFlagsAndAttributes. Se FILE_FLAG_OVERLAPPED não for especificado, o arquivo será aberto para E/S síncrona. Quando o arquivo é aberto para E/S assíncrona, um ponteiro para uma estrutura OVERLAPPED é passado para a chamada para ReadFile e WriteFile. Ao executar E/S síncronas, essa estrutura não é necessária em chamadas para ReadFile e WriteFile.

Observação

Se um arquivo ou dispositivo for aberto para E/S assíncrona, as chamadas subsequentes para funções como WriteFile usando esse identificador geralmente retornam imediatamente, mas também podem se comportar de forma síncrona em relação à execução bloqueada. Para obter mais informações, consulte E/S de disco assíncrono aparece como síncrona no Windows.

Embora CreateFile seja a função mais comum a ser usada para abrir ficheiros, volumes de disco, pipes anónimos e outros dispositivos semelhantes, as operações de E/S também podem ser executadas usando um typecast de handle de outros objetos do sistema, como um socket criado pelas funções socket ou accept.

Os identificadores para objetos de diretório são obtidos ao chamar a função CreateFile com o atributo FILE_FLAG_BACKUP_SEMANTICS. Os identificadores de diretório quase nunca são usados — os aplicativos de backup são um dos poucos aplicativos que normalmente os usam.

Depois de abrir o objeto de arquivo para E/S assíncrona, uma estrutura OVERLAPPED deve ser criada corretamente, inicializada e passada em cada chamada para funções como ReadFile e WriteFile. Tenha em mente o seguinte ao usar a estrutura OVERLAPPED em operações assíncronas de leitura e gravação:

  • Não desaloque ou modifique a estrutura OVERLAPPED ou o buffer de dados até que todas as operações de E/S assíncronas para o objeto de arquivo tenham sido concluídas.
  • Se você declarar seu ponteiro para a estrutura OVERLAPPED como uma variável local, não saia da função local até que todas as operações de E/S assíncronas para o objeto de arquivo tenham sido concluídas. Se a função local for encerrada prematuramente, a estrutura OVERLAPPED sairá do escopo e ficará inacessível a quaisquer funções ReadFile ou WriteFile que encontrar fora dessa função.

Você também pode criar um evento e colocar o identificador na estrutura OVERLAPPED; as funções de espera podem então ser usadas para esperar pela conclusão da operação de Entrada/Saída, aguardando no identificador de eventos.

Como dito anteriormente, ao trabalhar com um identificador assíncrono, os aplicativos devem ter cuidado ao fazer determinações sobre quando liberar recursos associados a uma operação de E/S especificada nesse manipulador. Se o identificador for desalocado prematuramente, ReadFile ou WriteFile podem relatar incorretamente que a operação de E/S foi concluída. Além disso, a função WriteFile às vezes retorna TRUE com um valor GetLastError de ERROR_SUCCESS, mesmo que esteja usando um identificador assíncrono (que também pode retornar FALSE com ERROR_IO_PENDING). Programadores acostumados com o design de E/S síncrona geralmente liberam recursos de buffer de dados neste momento porque TRUE e ERROR_SUCCESS significam que a operação está concluída. No entanto, se portas de conclusão de E/S estiverem sendo usadas com esse identificador assíncrono, um pacote de conclusão também será enviado mesmo que a operação de E/S seja concluída imediatamente. Em outras palavras, se o aplicativo liberar recursos após WriteFile retornar TRUE com ERROR_SUCCESS além da rotina de porta de conclusão de E/S, ele terá uma condição de erro livre de duplas. Neste exemplo, a recomendação seria permitir que a rotina portuária de conclusão fosse a única responsável por todas as operações de liberação de tais recursos.

O sistema não mantém o ponteiro de ficheiro em handles assíncronos para ficheiros e dispositivos que suportam ponteiros de ficheiro (ou seja, dispositivos de pesquisa). Portanto, a posição do ficheiro deve ser passada para as funções de leitura e escrita nos membros de dados de deslocamento relacionados da estrutura OVERLAPPED. Para obter mais informações, consulte WriteFile e ReadFile.

A posição do ponteiro do arquivo para um identificador síncrono é mantida pelo sistema à medida que os dados são lidos ou gravados e também pode ser atualizada usando a função SetFilePointer ou SetFilePointerEx .

Um aplicativo também pode esperar no identificador de arquivo para sincronizar a conclusão de uma operação de E/S, mas isso requer extrema cautela. Cada vez que uma operação de E/S é iniciada, o sistema operacional define o identificador de arquivo para o estado não sinalizado. Cada vez que uma operação de E/S é concluída, o sistema operacional define o identificador de arquivo para o estado sinalizado. Portanto, se um aplicativo inicia duas operações de E/S e aguarda no identificador de arquivo, não há como determinar qual operação será concluída quando o identificador estiver definido para o estado sinalizado. Se um aplicativo precisar executar várias operações de E/S assíncronas em um único arquivo, ele deverá aguardar o identificador de evento na estrutura OVERLAPPED específica para cada operação de E/S, em vez de no identificador de arquivo comum.

Cancelando operações de E/S

Para cancelar todas as operações de E/S assíncronas pendentes, use:

  • CancelIo: Esta função cancela apenas as operações emitidas pelo thread de chamada para o identificador de arquivo especificado.
  • CancelIoEx: Esta função cancela todas as operações emitidas pelos threads para o identificador de arquivo especificado.

Use CancelSynchronousIo para cancelar operações de E/S síncronas pendentes.

As funções ReadFileEx e WriteFileEx permitem que um aplicativo especifique uma rotina a ser executada (consulte FileIOCompletionRoutine) quando a solicitação de E/S assíncrona for concluída.

WriteFile

ReadFile