La fonction CreateIoCompletionPort
permet la création d’un nouveau port d’achèvement d’E / S et l’enregistrement des CreateIoCompletionPort
de fichiers sur un port d’achèvement d’E / S existant.
Ensuite, je peux utiliser n’importe quelle fonction, comme une recv
sur un socket ou un fichier ReadFile
sur un fichier avec une structure OVERLAPPED
pour démarrer une opération asynchrone.
Je dois vérifier si l’appel de fonction est revenu de manière synchrone bien qu’il ait été appelé avec une structure OVERLAPPED
et dans ce cas, le gérer directement. Dans l’autre cas, lorsque ERROR_IO_PENDING
est renvoyé, je peux utiliser la fonction GetQueuedCompletionStatus
pour être averti lorsque l’opération se termine.
La question qui se pose sont:
Comment puis-je supprimer une poignée du port d’achèvement d’E / S? Par exemple, lorsque j’ajoute des sockets à l’IOCP, comment puis-je supprimer ceux qui sont fermés? Dois-je simplement réenregistrer un autre socket avec la même clé de complétion?
En outre, existe-t-il un moyen de passer les appels TOUJOURS sur le port d’achèvement des E / S et de ne pas retourner de manière synchrone?
Et enfin, est-il possible, par exemple, de recv
manière asynchrone mais d’ send
synchrone? Par exemple, lorsqu’un simple service d’écho est implémenté: puis-je attendre avec une recv
asynchrone pour de nouvelles données mais send
la réponse de manière synchrone afin de réduire la complexité du code? Dans mon cas, je ne recevrais pas une seconde fois avant le traitement de la première demande.
Que se passe-t-il si un ReadFile
asynchrone a été demandé, mais avant qu’il ne soit terminé, un WriteFile
dans le même fichier doit être traité. Le ReadFile
sera-t-il annulé avec un message d’erreur et je dois redémarrer le processus de lecture dès que l’écriture est terminée? Ou dois-je annuler le ReadFile
manuellement avant d’écrire? Cette question se pose en combinaison avec un appareil de communication; Ainsi, l’écriture et la lecture ne devraient pas poser de problèmes si elles se produisent simultanément.
Comment puis-je supprimer une poignée du port d’achèvement d’E / S?
Dans mon expérience, vous ne pouvez pas dissocier un handle d’un port d’achèvement. Toutefois, vous pouvez désactiver la notification de port d’achèvement en définissant le bit de hEvent
champ hEvent
de votre structure OVERLAPPED
: Consultez la documentation de GetQueuedCompletionStatus .
Par exemple, lorsque j’ajoute des sockets à l’IOCP, comment puis-je supprimer ceux qui sont fermés? Dois-je simplement réenregistrer un autre socket avec la même clé de complétion?
Il n’est pas nécessaire de dissocier explicitement un handle d’un port d’achèvement d’E / S; fermer la poignée est suffisant. Vous pouvez associer plusieurs descripteurs avec la même clé de complétion; La meilleure façon de déterminer quelle requête est associée à l’achèvement des E / S est d’utiliser la structure OVERLAPPED
. En fait, vous pouvez même étendre OVERLAPPED
pour stocker des données supplémentaires.
En outre, existe-t-il un moyen de passer les appels TOUJOURS sur le port d’achèvement des E / S et de ne pas retourner de manière synchrone?
C’est le comportement par défaut, même lorsque ReadFile
/ WriteFile
renvoie TRUE
. Vous devez explicitement appeler SetFileCompletionNotificationModes pour indiquer à Windows de ne pas mettre en queue un paquet d’achèvement lorsque TRUE
et ERROR_SUCCESS
sont renvoyés.
est-il possible par exemple de
recv
manière asynchrone mais d’send
synchrone?
Pas en utilisant recv
et send
; Vous devez utiliser des fonctions qui acceptent les structures OVERLAPPED
, telles que WSARecv
, WSASend
ou, en variante, ReadFile
et WriteFile
. Il peut être plus pratique d’utiliser cette dernière si votre code est destiné à gérer plusieurs types de descripteurs d’E / S, tels que les sockets et les canaux nommés. Ces fonctions fournissent un mode synchrone, donc si vous les utilisez, vous pouvez combiner des appels asynchrones et synchrones.
Que se passe-t-il si un ReadFile asynchrone a été demandé, mais avant qu’il ne soit terminé, un WriteFile dans le même fichier doit être traité?
Il n’y a pas d’annulation implicite. Tant que vous utilisez des structures OVERLAPPED
séparées pour chaque lecture / écriture sur un périphérique full-duplex, je ne vois aucune raison pour laquelle vous ne pouvez pas effectuer des opérations d’E / S simultanées.
Comme je l’ai déjà souligné, la croyance répandue selon laquelle il est impossible de supprimer les poignées des ports d’achèvement est erronée, probablement à cause de l’absence de toute indication sur la façon de procéder à partir de presque toute la documentation. En fait, c’est assez facile:
Appelez NtSetInformationFile
avec la valeur d’énumérateur FileReplaceCompletionInformation
pour FileInformationClass
et un pointeur vers une structure FILE_COMPLETION_INFORMATION
pour le paramètre FileInformation
. Dans cette structure, définissez le membre Port
sur NULL
(ou nullptr
, en C ++) pour dissocier le fichier du port auquel il est actuellement connecté (je suppose que si ce fichier n’est associé à aucun port, rien ne se produirait) ou définissez Port
sur un HANDLE
valide à un autre port d’achèvement pour associer le fichier à celui-ci à la place.
D’abord quelques corrections importantes.
Si l’opération d’E / S superposées se termine immédiatement ( ReadFile
ou une fonction d’E / S similaire renvoie un succès) – la finalisation des E / S est déjà planifiée pour l’IOCP.
En outre, en fonction de vos questions, je pense que vous confondez les poignées de fichier / socket et les opérations d’E / S spécifiques émises sur ces dernières.
Maintenant, en ce qui concerne vos questions:
Une question plus correcte devrait être comment le fichier / socket doit être correctement fermé. La réponse est: fermez simplement votre poignée. Toutes les opérations d’E / S en suspens (émises sur cette poignée) reviendront bientôt avec un code d’erreur (avortement). Ensuite, dans votre routine d’achèvement (celle qui appelle GetQueuedCompletionStatus
dans une boucle), vous GetQueuedCompletionStatus
effectuer le nettoyage nécessaire pour chaque E / S.
Comme je l’ai déjà dit, toutes les entrées / sorties arrivent à IOCP dans des cas synchrones et asynchrones. La seule situation où il ne parvient pas à IOCP est quand une E / S se termine de manière synchrone avec une erreur . Quoi qu’il en soit, si vous souhaitez un traitement unifié – dans ce cas, vous pouvez PostQueuedCompletionStatus
données de complétion artificielles à IOCP (utilisez PostQueuedCompletionStatus
).
Vous devez utiliser WSASend
et WSARecv
(pas recv
et send
) pour les E / S superposées. Néanmoins, même le socket a été ouvert avec l’indicateur WSA_FLAG_OVERLAPPED
– vous êtes autorisé à appeler les fonctions d’E / S sans spécifier la structure OVERLAPPED
. Dans ce cas, ces fonctions fonctionnent de manière synchrone. Vous pouvez donc choisir des modes synchrones / asynchrones pour chaque appel de fonction.
Il n’y a pas de problème à mélanger les requêtes de lecture / écriture superposées. Le seul point délicat est ce qui se passe si vous essayez de lire les données à partir de la position du fichier où vous écrivez actuellement. Le résultat peut dépendre de choses subtiles, telles que l’ordre d’achèvement des E / S par le matériel, certains parameters de synchronisation du PC, etc. Une telle situation doit être évitée.
Comment puis-je supprimer une poignée du port d’achèvement d’E / S? Par exemple, lorsque j’ajoute des sockets à l’IOCP, comment puis-je supprimer ceux qui sont fermés? Dois-je simplement réenregistrer un autre socket avec la même clé de complétion?
Vous l’avez mal compris. Vous définissez le port d’achèvement d’E / S à utiliser par un object fichier – lorsque l’object fichier est supprimé, vous n’avez rien à craindre. La raison pour laquelle vous vous trompez est la manière dont Win32 expose la fonctionnalité de l’API native sous-jacente ( CreateIoCompletionPort
fait deux choses très différentes en une seule fonction).
En outre, existe-t-il un moyen de passer les appels TOUJOURS sur le port d’achèvement des E / S et de ne pas retourner de manière synchrone?
C’est comme ça que ça a toujours été. À partir de Windows Vista uniquement, vous pouvez personnaliser la gestion des notifications d’achèvement.
Que se passe-t-il si un ReadFile asynchrone a été demandé, mais avant qu’il ne soit terminé, un WriteFile dans le même fichier doit être traité. Le fichier de lecture sera-t-il annulé avec un message d’erreur et je dois redémarrer le processus de lecture dès que l’écriture est terminée?
Les opérations d’E / S sous Windows sont insortingnsèquement asynchrones et les requêtes sont toujours en attente. Vous ne le pensez peut-être pas, car vous devez spécifier FILE_FLAG_OVERLAPPED
dans CreateFile
pour activer les E / S asynchrones. Cependant, au niveau de la couche native, les E / S synchrones sont vraiment un complément, ce qui permet au kernel de garder une trace de la position du fichier et d’attendre que les E / S se terminent avant de retourner.