8
votes

Suppression d'une poignée d'un port d'achèvement des E / S et d'autres questions sur IOCP

the CateIocompletionPort fonction permet de créer un nouveau port d'achèvement d'E / S et l'enregistrement des poignées de fichier à un port d'achèvement d'E / S existant.

Ensuite, je peux utiliser n'importe quelle fonction, comme un RECV sur une prise ou un listifile sur un fichier avec un superposé Structure une opération asynchrone.

Je dois vérifier si l'appel de la fonction renvoyé de manière synchrone, bien qu'il ait été appelé avec une structure superposé et dans ce cas, la poignée directement. Dans l'autre cas, lorsque error_io_pending est renvoyé, je peux utiliser le GetQueSueCompletionStatus fonction à notifier lorsque l'opération est terminée.

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 des fermées? Devrais-je simplement ré-enregistrer une autre prise avec la même clé d'achèvement?

  • En outre, est-il un moyen de rendre les appels toujours passer sur le port d'achèvement d'E / S et ne retournez pas de manière synchrone?

  • et enfin, est-il possible par exemple de RECV asynchrone mais à envoyer de manière synchrone? Par exemple, lorsqu'un service d'écho simple est implémenté: puis-je attendre avec un asynchrone recv pour de nouvelles données mais envoyer la réponse de manière synchrone afin que la complexité du code soit réduite? Dans mon cas, je ne serais pas recv une seconde fois de toute façon avant la première demande de la première demande.

  • Que se passe-t-il si un asynchrone a été demandé, mais avant de terminer, un wrôlerfile dans le même fichier doit être traité. Est-ce que le listerfile est-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 listerfile manuellement avant d'écrire? Cette question se pose en combinaison avec un dispositif de communication; Donc, l'écriture et la lecture ne doivent pas faire des problèmes si cela se passe simultanément.


0 commentaires

4 Réponses :


11
votes

Comment puis-je supprimer une poignée du port d'achèvement d'I / S?

Dans mon expérience, vous ne pouvez pas dissocier une poignée d'un port d'achèvement. Toutefois, vous pouvez désactiver la notification de port d'achèvement en définissant le bit à faible commande de votre de la structure HEVENT de la structure: voir la documentation pour GetQueSueCompletionStatus .

Par exemple, lorsque j'ajoute des sockets à l'IOCP, comment puis-je supprimer les fermés? Devrais-je simplement ré-enregistrer une autre prise avec la même clé d'achèvement?

Il n'est pas nécessaire de dissocier explicitement une poignée d'un port d'achèvement d'E / S; la fermeture de la poignée est suffisante. Vous pouvez associer plusieurs poignées avec la même clé d'achèvement; La meilleure façon de déterminer quelle demande est associée à l'achèvement d'E / S consiste à utiliser la structure superposée . En fait, vous pouvez même étendre chevauché pour stocker des données supplémentaires.

Aussi, est-il un moyen de rendre les appels toujours sur le port d'achèvement d'E / S et ne retournez pas de manière synchrone?

C'est le comportement par défaut, même lorsque listifile / warserfile renvoie true . Vous devez expliquer explicitement SetFilecompletimotificationModes pour dire Windows à Pas en faise un paquet d'achèvement lorsque true et error_success est retourné.

est-il possible par exemple de recv asynchrone mais à envoyer synchrone?

pas à l'aide de RECV et Envoyer ; Vous devez utiliser des fonctions qui acceptent les structures superposées , telles que wsaRecv , wsasend ou alternativement listifile et wrôlerfile . Il peut être plus pratique d'utiliser ce dernier si votre code est destiné à travailler plusieurs types de poignées d'E / S, telles que les deux sockets et les tuyaux nommés. Ces fonctions fournissent un mode synchrone, donc si vous utilisez ceux-ci, vous pouvez mélanger des appels asynchrones et synchrones.

Que se passe-t-il si un fichier de lecture asynchrone a été demandé, mais avant qu'il ne termine, un fichier d'écriture au même fichier doit être traité?

Il n'y a pas d'annulation implicite. Tant que vous utilisez des structures Séparez pour chaque lecture / écriture sur un périphérique en duplex intégral, je ne vois aucune raison pour que vous ne puissiez pas faire des opérations d'E / S simultanées.


1 commentaires

"Cependant, vous pouvez désactiver la notification du port d'achèvement en définissant le bit à faible commande de votre champ Hentit de la structure superposée". Je n'ai pas pu désactiver la notification de port d'achèvement pour une prise donnée à l'aide de cette option. Mon cas: (1) Créez une prise, (2) Ajouter au port d'achèvement, (3) Appel WSARECV, (4) s'il renvoie WSA_IO_PENDING - OK, (5) si elle renvoie erros_success -> Je veux fermer immédiatement le socket et ne recevez pas de notification sur cette prise dans le port d'achèvement



3
votes

d'abord quelques corrections importantes.

Dans le cas où l'opération d'E / S chevauchée complète immédiatement ( listifile ou une fonction d'E / S similaire renvoie le succès) - L'achèvement d'E / S est déjà prévu à l'IOCP .

En outre, selon vos questions, je pense que vous confondez entre les poignées de fichier / prise et les opérations d'E / S spécifiques émises sur elles.

Maintenant, en ce qui concerne vos questions:

  1. AFAIK Il n'y a pas de moyen classique de supprimer une poignée de fichier / prise de l'IOCP (généralement, vous n'avez tout simplement pas à le faire). Vous parlez de supprimer les poignées fermées de l'IOCP, qui est absolument incorrecte. Vous ne pouvez plus retirer une poignée fermée, car elle ne fait plus référence à un objet de noyau valide!

    Une question plus correcte doit être la manière dont le fichier / socket doit être correctement fermé. La réponse est la suivante: ferme votre poignée. Toutes les opérations d'E / S en circulation (émises sur cette poignée) reviendront bientôt avec un code d'erreur (avortement). Ensuite, dans votre routine d'achèvement (celle qui appelle getQueDeccleTionnstatus dans une boucle) devrait effectuer le nettoyage nécessaire par Per-I / O.

    1. Comme je l'ai déjà dit, toute l'achèvement d'E / S arrive à IOCP dans des cas synchrones et asynchrones. La seule situation où il n'arrive pas à IOCP est quand un E / S complète de manière synchrone avec une erreur . Quoi qu'il en soit, si vous souhaitez un traitement unifié - dans un tel cas, vous pouvez afficher une donnée d'achèvement artificielle à IOCP (utilisation postquacéeCompletionStatus ).

    2. Vous devez utiliser wsaSend et wsaecv (pas recv et envoi ) pour i / O. Néanmoins, même du socket a été ouvert avec le drapeau wsa_flag_overlapped - vous êtes autorisé d'appeler les fonctions d'E / S sans spécifier la structure superposée . Dans ce cas, ces fonctions fonctionnent de manière synchrone. Afin que vous puissiez choisir des modes synchrones / asynchrones pour chaque appel de fonction.

    3. Il n'y a pas de problème à mélanger des demandes de lecture / d'écriture recouvertes. Le seul point délicat est ce qui se passe ici si vous essayez de lire les données de la position de 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 paramètres de chronométrage PC et etc. Une telle situation doit être évitée.


2 commentaires

Si une opération recouverte se termine immédiatement, WSARECV renvoie une valeur de zéro et le paramètre LPNumberOfByTesRecvd est mis à jour avec le nombre d'octets reçus et les bits d'indicateur indiqués par le paramètre LPFLAGS sont également mis à jour. Si l'opération recouverte est initiée et complétera plus tard, WsaRecv renvoie Socket_Error et indique le code d'erreur WSA_IO_PENDING. Pourquoi mentionnent-ils le cas où l'opération réussit et se termine de manière synchrone alors s'il n'est pas possible de se produire?


Il est possible. C'est ce qui arrive parfois. De plus, pour le fichier E / S, c'est ce qui se passe habituellement (les E / SHO asynchrones sont rares dans des conditions normales).



0
votes

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 des fermées? Devrais-je simplement ré-enregistrer une autre prise avec la même clé d'achèvement?

Vous avez le mauvais chemin autour. Vous définissez le port d'achèvement d'E / S à utiliser par un objet de fichier - lorsque l'objet de fichier est supprimé, vous n'avez rien à craindre. La raison pour laquelle vous êtes confus est à cause de la façon dont Win32 expose la fonctionnalité API native sous-jante ( CreateIocompletionPort fait deux choses très différentes en une seule fonction).

aussi, y a-t-il un moyen de faire les appels Toujours aller sur le port d'achèvement des E / S et ne revenez pas de manière synchrone?

Voici comment ça a toujours été. En commençant par Windows Vista, pouvez-vous personnaliser la manière dont les notifications d'achèvement sont traitées.

Que se passe-t-il si une asynchrone Listerfile a été demandé, mais Avant de compléter, un wrtorfile à Le même fichier doit être traité. Le fichier 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 complet?

Les opérations d'E / S sous Windows sont asynchrones de manière inhérale et les demandes sont toujours en file d'attente. Vous ne pouvez pas penser que ceci est donc parce que vous devez spécifier file_flag_overlapcid dans créeefile pour activer les E / S asynchrones. Cependant, à la couche indigène, les E / S synchrones sont vraiment un complément, une chose de commodité où le noyau conserve la piste de la position du fichier et attend que les E / S complètent avant de retourner.


0 commentaires

9
votes

Comme je l'ai déjà signalé , la croyance généralement tenue qu'il est impossible de supprimer les poignées des ports d'achèvement, c'est faux , probablement causé par l'abscence de tout indice quant à la façon de le faire de presque toutes les documents que je pouvais trouver. En fait, c'est assez facile:

appeler NTSETTINformationFile avec le filereplacecompletionInformation Enumerator Valeur pour FileInformationClass et un pointeur sur un file_completion_information structure pour le FileInformation < / code> paramètre. Dans cette structure, définissez le membre port sur null (ou nullptr , en C ++) pour dissocier le fichier du port, il est actuellement attaché à ( Je suppose que si ce n'est pas attaché à aucun port, rien ne se passerait), ou définir port sur une poignée valide à un autre port d'achèvement pour associer le fichier avec celui-ci à la place.


2 commentaires

Remarque: Si vous suivez le lien vers les documents file_combletion_information, vous verrez "Cette structure est disponible à partir de Windows 8.1."


Mais est-ce disponible dans l'espace utilisateur?