Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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. A E/S assíncrona também é chamada de E/S sobreposta.
Na E/S de arquivo síncrona, um thread inicia uma operação de E/S e imediatamente entra em um estado de espera até que a solicitação de E/S seja concluída. Um thread que executa a E/S de arquivo assíncrona 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 de que a operação de E/S foi 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.
Quando é esperado que uma solicitação de E/S leve muito 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 costuma ser 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 de sinais de kernel pode tornar a E/S assíncrona menos interessante, especialmente se for necessário fazer várias operações de E/S rápidas. Nesse caso, a E/S síncrona seria mais indicada. Os mecanismos e os detalhes de implementação de como realizar essas tarefas variam dependendo do tipo de identificador de dispositivo usado e das necessidades específicas do aplicativo. Em outras palavras, geralmente existem várias maneiras de resolver o problema.
Considerações de E/S síncrona e assíncrona
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 um dos seguintes eventos ocorra:
- A operação de E/S é concluída (uma gravação de dados, neste exemplo).
- Ocorre um erro de E/S. (Por exemplo, o pipe é fechado na outra extremidade.)
- Ocorreu um erro na própria chamada (por exemplo, um ou mais parâmetros não são válidos).
- Outra thread no processo chama a função CancelSynchronousIo usando o identificador de thread bloqueado, que encerra a E/S desse thread, resultando na falha da 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, e os designers de aplicativos devem considerar o uso de E/S assíncrona com objetos de sincronização de thread apropriados, tais como portas de conclusão de E/S. Para obter mais informações sobre sincronização de threads, consulte Sobre sincronização.
Um processo abre um arquivo para E/S assíncrona em sua chamada para CreateFile especificando o flag FILE_FLAG_OVERLAPPED no parâmetro dwFlagsAndAttributes. Se FILE_FLAG_OVERLAPPED não for especificado, o arquivo será aberto para a 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 a E/S síncrona, 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, chamadas subsequentes para funções como WriteFile usando esse identificador geralmente retornarão imediatamente, mas também poderão se comportar de forma síncrona em relação à execução bloqueada. Para mais informações, consulte E/S assíncrona de disco aparece como síncrona no Windows.
Embora CreateFile seja a função mais comum a ser usada para abrir arquivos, volumes de disco, pipes anônimos e outros dispositivos semelhantes, as operações de E/S também podem ser executadas usando um handle typecast de outros objetos do sistema, como um socket criado pelas funções socket ou accept.
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; aplicativos de backup são um dos poucos que normalmente os usam.
Depois de abrir o objeto de arquivo para E/S assíncrona, uma estrutura OVERLAPPED deve ser criada, inicializada e passada corretamente para cada chamada para funções como ReadFile e WriteFile. Tenha o seguinte em mente 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 o 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 para qualquer função ReadFile ou WriteFile que encontrar fora dessa função.
Você também pode criar um evento e colocar o handle na estrutura OVERLAPPED. As funções de espera (wait functions) podem ser usadas para aguardar a conclusão da operação de E/S aguardando o handle do evento.
Conforme já mencionado, 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 identificador. Se o identificador for desalocado prematuramente, ReadFile ou WriteFile poderão relatar incorretamente que a operação de E/S está concluída. Além disso, a função WriteFile às vezes retornará 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). Os programadores que estão acostumados ao design de E/S síncrona geralmente liberam recursos de buffer de dados neste ponto porque TRUE e ERROR_SUCCESS significam que a operação foi concluída. No entanto, se as 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 tenha sido concluída imediatamente. Em outras palavras, se o aplicativo liberar recursos depois que 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 double-free. Neste exemplo, a recomendação seria permitir que a rotina de porta de conclusão seja a única responsável por todas as operações de liberação desses recursos.
O sistema não mantém o ponteiro de arquivo em identificadores assíncronos para arquivos e dispositivos que dão suporte a ponteiros de arquivo (ou seja, dispositivos de busca); portanto, a posição do ponteiro de arquivo deve ser passada para as funções de leitura e gravação nos membros de dados de deslocamento correspondentes na estrutura OVERLAPPED. Para obter mais informações, consulte WriteFile e ReadFile.
A posição do ponteiro de arquivo para um identificador síncrono é mantida pelo sistema conforme 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 aguardar o identificador de arquivo para sincronizar a conclusão de uma operação de E/S, mas isso requer muito cuidado. 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 não sinalizado. Portanto, se um aplicativo iniciar duas operações de E/S e aguardar o identificador do arquivo, não haverá como determinar qual operação será concluída quando o identificador for 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 no 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: essa função cancela apenas as operações emitidas pelo thread de chamada para o identificador de arquivo especificado.
- CancelIoEx: essa 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.