E/S synchrones et asynchrones

Consultez également exemples d’applications liées aux E/S.

Il existe deux types de synchronisation d’entrée/sortie (E/S) : les E/S synchrones et les E/S asynchrones. Les E/S asynchrones sont également appelées E/S qui se chevauchent.

Dans les E/S de fichiers synchrones, un thread démarre une opération d’E/S et entre immédiatement dans un état d’attente jusqu’à ce que la demande d’E/S soit terminée. Un thread effectuant des E/S de fichier asynchrones envoie une demande d’E/S au noyau en appelant une fonction appropriée. Si la demande est acceptée par le noyau, le thread appelant continue de traiter un autre travail jusqu’à ce que le noyau signale au thread que l’opération d’E/S est terminée. Il interrompt ensuite sa tâche actuelle et traite les données de l’opération d’E/S si nécessaire.

Les deux types de synchronisation sont illustrés dans la figure suivante.

e/s synchrones et asynchrones

Dans les situations où une demande d’E/S est censée prendre beaucoup de temps, comme une actualisation ou une sauvegarde d’une base de données volumineuse ou une liaison de communication lente, les E/S asynchrones sont généralement un bon moyen d’optimiser l’efficacité du traitement. Toutefois, pour les opérations d’E/S relativement rapides, la surcharge liée au traitement des demandes d’E/S du noyau et des signaux du noyau peut rendre les E/S asynchrones moins bénéfiques, en particulier si de nombreuses opérations d’E/S rapides doivent être effectuées. Dans ce cas, les E/S synchrones seraient meilleures. Les mécanismes et les détails d’implémentation de la façon d’accomplir ces tâches varient en fonction du type de handle d’appareil utilisé et des besoins particuliers de l’application. En d’autres termes, il existe généralement plusieurs façons de résoudre le problème.

Considérations relatives aux E/S synchrones et asynchrones

Si un fichier ou un appareil est ouvert pour les E/S synchrones (autrement dit, FILE_FLAG_OVERLAPPED n’est pas spécifié), les appels ultérieurs à des fonctions telles que WriteFile peuvent bloquer l’exécution du thread appelant jusqu’à ce que l’un des événements suivants se produise :

  • L’opération d’E/S se termine (dans cet exemple, une écriture de données).
  • Une erreur d’E/S se produit. (Par exemple, le canal est fermé à partir de l’autre extrémité.)
  • Une erreur a été générée dans l’appel lui-même (par exemple, un ou plusieurs paramètres ne sont pas valides).
  • Un autre thread dans le processus appelle la fonction CancelSynchronousIo à l’aide du handle de thread du thread bloqué, qui met fin aux E/S pour ce thread, en échouant l’opération d’E/S.
  • Le thread bloqué est arrêté par le système ; par exemple, le processus lui-même est terminé ou un autre thread appelle la fonction TerminateThread à l’aide du handle du thread bloqué. (Ceci est généralement considéré comme un dernier recours et une conception d’application pas bonne.)

Dans certains cas, ce délai peut être inacceptable pour la conception et l’objectif de l’application. Par conséquent, les concepteurs d’applications doivent envisager d’utiliser des E/S asynchrones avec des objets de synchronisation de threads appropriés, tels que des ports d’achèvement d’E/S. Pour plus d’informations sur la synchronisation de threads, consultez À propos de la synchronisation.

Un processus ouvre un fichier pour les E/S asynchrones dans son appel à CreateFile en spécifiant l’indicateur FILE_FLAG_OVERLAPPED dans le paramètre dwFlagsAndAttributes . Si FILE_FLAG_OVERLAPPED n’est pas spécifié, le fichier est ouvert pour les E/S synchrones. Lorsque le fichier a été ouvert pour les E/S asynchrones, un pointeur vers une structure CHEVAUCHEMENT EST passé dans l’appel à ReadFile et WriteFile. Lors de l’exécution d’E/S synchrones, cette structure n’est pas requise dans les appels à ReadFile et WriteFile.

Notes

Si un fichier ou un appareil est ouvert pour les E/S asynchrones, les appels suivants à des fonctions telles que WriteFile à l’aide de cette gestion retournent généralement immédiatement, mais peuvent également se comporter de manière synchrone en ce qui concerne l’exécution bloquée. Pour plus d’informations, consultez https://support.microsoft.com/kb/156932.

 

Bien que CreateFile soit la fonction la plus courante à utiliser pour l’ouverture de fichiers, de volumes de disque, de canaux anonymes et d’autres appareils similaires, les opérations d’E/S peuvent également être effectuées à l’aide d’un handle typecast à partir d’autres objets système tels qu’un socket créé par le socket ou les fonctions d’acceptation .

Les handles des objets d’annuaire sont obtenus en appelant la fonction CreateFile avec l’attribut FILE_FLAG_BACKUP_SEMANTICS . Les handles d’annuaire ne sont presque jamais utilisés. Les applications de sauvegarde sont l’une des rares applications qui les utiliseront généralement.

Après avoir ouvert l’objet file pour les E/S asynchrones, une structure CHEVAUCHEMENT DOIT être correctement créée, initialisée et passée dans chaque appel à des fonctions telles que ReadFile et WriteFile. Gardez à l’esprit ce qui suit lors de l’utilisation de la structure CHEVAUCHEMENT DANS des opérations asynchrones de lecture et d’écriture :

  • Ne libérez pas ou ne modifiez pas la structure CHEVAUCHEMENT OU la mémoire tampon de données tant que toutes les opérations d’E/S asynchrones sur l’objet de fichier n’ont pas été effectuées.
  • Si vous déclarez votre pointeur vers la structure CHEVAUCHEMENT EN tant que variable locale, ne quittez pas la fonction locale tant que toutes les opérations d’E/S asynchrones sur l’objet fichier n’ont pas été effectuées. Si la fonction locale est supprimée prématurément, la structure OVERLAPPED sort de l’étendue et elle sera inaccessible aux fonctions ReadFile ou WriteFile qu’elle rencontre en dehors de cette fonction.

Vous pouvez également créer un événement et placer le handle dans la structure CHEVAUCHEMENT ; les fonctions d’attente peuvent ensuite être utilisées pour attendre la fin de l’opération d’E/S en attendant sur le handle d’événement.

Comme indiqué précédemment, lorsqu’elles utilisent un handle asynchrone, les applications doivent faire attention lorsqu’elles déterminent quand libérer les ressources associées à une opération d’E/S spécifiée sur ce handle. Si le handle est libéré prématurément, ReadFile ou WriteFile peut signaler à tort que l’opération d’E/S est terminée. En outre, la fonction WriteFile retourne parfois TRUE avec une valeur GetLastErrorde ERROR_SUCCESS, même si elle utilise un handle asynchrone (qui peut également retourner FALSE avec ERROR_IO_PENDING). Les programmeurs habitués à la conception d’E/S synchrones publient généralement des ressources de mémoire tampon de données à ce stade, car TRUE et ERROR_SUCCESS signifient que l’opération est terminée. Toutefois, si des ports d’achèvement d’E/ S sont utilisés avec ce handle asynchrone, un paquet d’achèvement sera également envoyé même si l’opération d’E/S s’est terminée immédiatement. En d’autres termes, si l’application libère des ressources après que WriteFile retourne TRUE avec ERROR_SUCCESS en plus de dans la routine du port d’achèvement d’E/S, elle aura une condition d’erreur doublement libre. Dans cet exemple, la recommandation consisterait à autoriser la routine de port d’achèvement à être seule responsable de toutes les opérations de libération de ces ressources.

Le système ne gère pas le pointeur de fichier sur les handles asynchrones vers les fichiers et les appareils qui prennent en charge les pointeurs de fichiers (c’est-à-dire la recherche d’appareils). Par conséquent, la position du fichier doit être transmise aux fonctions de lecture et d’écriture dans les membres de données offset associées de la structure CHEVAUCHEMENT . Pour plus d’informations, consultez WriteFile et ReadFile.

La position du pointeur de fichier pour un handle synchrone est conservée par le système à mesure que les données sont lues ou écrites et peuvent également être mises à jour à l’aide de la fonction SetFilePointer ou SetFilePointerEx .

Une application peut également attendre le handle de fichier pour synchroniser l’achèvement d’une opération d’E/S, mais cela nécessite une extrême prudence. Chaque fois qu’une opération d’E/S est démarrée, le système d’exploitation définit le handle de fichier à l’état non signé. Chaque fois qu’une opération d’E/S est terminée, le système d’exploitation définit le handle de fichier à l’état signalé. Par conséquent, si une application démarre deux opérations d’E/S et attend sur le handle de fichier, il n’existe aucun moyen de déterminer quelle opération est terminée lorsque le handle est défini à l’état signalé. Si une application doit effectuer plusieurs opérations d’E/S asynchrones sur un seul fichier, elle doit attendre sur le handle d’événement dans la structure CHEVAUCHÉE spécifique pour chaque opération d’E/S, plutôt que sur le handle de fichier commun.

Pour annuler toutes les opérations d’E/S asynchrones en attente, utilisez :

  • CancelIo : cette fonction annule uniquement les opérations émises par le thread appelant pour le handle de fichier spécifié.
  • CancelIoEx : cette fonction annule toutes les opérations émises par les threads pour le handle de fichier spécifié.

Utilisez CancelSynchronousIo pour annuler les opérations d’E/S synchrones en attente.

Les fonctions ReadFileEx et WriteFileEx permettent à une application de spécifier une routine à exécuter (voir FileIOCompletionRoutine) une fois la demande d’E/S asynchrone terminée.