Est-il possible de changer POIGNÉE qui a été ouvert pour synchrone E / S à ouvrir pour E / S asynchrone au cours de sa durée de vie?

StackOverflow https://stackoverflow.com/questions/2475713

Question

La plupart de mon travail de programmation quotidienne dans Windows est de nos jours autour des opérations d'E / S de toutes sortes (tuyaux, consoles, fichiers, prises, ...). Je suis bien au courant des différentes méthodes de lecture et d'écriture de / vers différents types de poignées (synchrone, asynchrone en attente d'achèvement sur les événements, en attente sur les handles de fichiers, d'E / S ports d'achèvement, et alertable E / S). Nous utilisons beaucoup de ceux-ci.

Pour certaines de nos applications, il serait très utile d'avoir une seule façon de traiter toutes les poignées. Je veux dire, le programme ne peut pas savoir, quel type de poignée, il a reçu et nous aimerions utiliser, disons, les ports d'achèvement d'E / S pour tous.

Alors d'abord je demanderais:

Supposons que j'ai une poignée:

HANDLE h;

qui a été reçu par mon processus pour E / S de quelque part. Est-il un moyen facile et fiable pour savoir quels drapeaux il a été créé avec? Le principal indicateur en question est FILE_FLAG_OVERLAPPED.

La seule façon de me connaître jusqu'à présent, est d'essayer d'enregistrer cette poignée dans le port d'achèvement d'E / S (en utilisant CreateIoCompletionPort()). Si cela réussit la poignée a été créé avec FILE_FLAG_OVERLAPPED. Mais seul port d'achèvement d'E / S doit être utilisé, comme la poignée ne peut pas être désinscrit de sans fermer la HANDLE de h lui-même.

il y a une Fournir un moyen facile de déterminer la présence de FILE_FLAG_OVERLAPPED, viendrait ma deuxième question:

Est-il possible comment ajouter ce drapeau à la poignée déjà existante? Cela ferait une poignée qui a été à l'origine ouverte pour les opérations synchrones sont ouverts à l'asynchrone. Y aurait-il un moyen comment créer opposé (enlever le FILE_FLAG_OVERLAPPED pour créer poignée synchrone en asynchrone)?

Je n'ai trouvé aucune façon directe après avoir lu MSDN et googler beaucoup. Y aurait-il au moins un truc qui pourrait faire la même chose? Comme recréant la poignée de la même façon d'utiliser la fonction CreateFile() ou quelque chose de similaire? Quelque chose même partiellement documenté ou non documenté du tout?

Le lieu principal où je besoin de cela, est de déterminer la façon dont la (ou changer la façon dont) le processus doit en lecture / écriture de poignées qui lui sont envoyées par des applications tierces. Nous ne pouvons pas contrôler la façon dont des produits tiers, créer leurs poignées.

Cher de Windows gourous: aide s'il vous plaît

En ce qui concerne

Martin

Était-ce utile?

La solution 2

3 années ont passé et Windows 8 a été libéré. Merci à la régression introduite dans la mise en œuvre de la console dans Windows 8 je suis arrivé à faire quelque chose au sujet de la question qui a déclenché cette question. Donc, je l'ai finalement essayé d'utiliser l'appel de fonction ReOpenFile ().

Dans une phrase:. Pour mes fins, il est inutile

L'API ReOpenFile () est utilisé pour « prendre une poignée de fichier existant et obtenir une autre poignée qui a un ensemble différent de droits d'accès ». Au moins ce qui est indiqué dans le l'article original.

J'ai essayé d'utiliser la ReOpenFile () sur la poignée d'entrée de la console:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

Et ce que je reçois est: erreur 1168: « élément introuvable ». « Merci Microsoft ». Je ne vais pas même essayer de l'utiliser pour les tuyaux anonymes, étant donné que la documentation indique:

« (Asynchronous) chevauchés lecture et d'écriture ne sont pas pris en charge par des tuyaux anonymes. Cela signifie que vous ne pouvez pas utiliser les fonctions ReadFileEx et WriteFileEx avec des tuyaux anonymes. De plus, est ignoré le paramètre lpOverlapped de ReadFile et WriteFile lorsque ces fonctions sont utilisées avec des tuyaux anonymes. »

Merci, les gens, tous pour vos suggestions. Lors de la lecture de la poignée de manière asynchrone, on doit être prêt aussi pour le fait que l'opération peut terminer de façon synchrone. Ce que je sais. La principale raison pour laquelle je pose cette question est:

lorsqu'une lecture synchrone a été émis sur certains objets (tuyaux au moins anonyme, et l'entrée de la console dans Windows 8), puis d'appeler CloseHandle () d'un autre fil sur la même poignée sera soit échouer, ou suspendre, jusqu'à ce que le ReadFile () battant; cela signifie qu'il se bloque indéfiniment dans de nombreux cas. Telle est la raison pour laquelle je voulais remplacer la poignée synchrone asynchrone.

Maintenant, il est clair pour moi qu'il est tout simplement impossible dans les systèmes d'exploitation Windows pour annuler certaines opérations de lecture de manière simple. Lors de la lecture de poignées synchrones, il faut juste sortir de l'application même si ReadFile () est en train de lire encore d'une poignée dans un fil, car il est tout simplement impossible de se réveiller de manière fiable une telle opération de lecture. En savoir ... Dans les nouvelles OS, il est possible d'annuler cette opération. Cependant, il n'y a aucun moyen de savoir temps le fil est déjà, ou pas encore dans l'appel ReadFile (). Si ReadFile () est pas encore appelé alors il n'y a pas d'opération pour annuler et lecture ultérieure se bloque. La seule façon serait de fermer la poignée, mais cette opération se bloque ou échoue sur certains objets et sur certains systèmes d'exploitation. La seule solution appropriée à cette question est d'E / S asynchrone. Mais, comme je l'ai mentionné au début, notre APP est lancé par des applications tiers et nous ne pouvons pas les forcer tous à toujours créer des canaux nommés avec jeu de drapeau chevauchée pour le stdio.

Je donne et va mettre en œuvre hacks laid méchant ... nous devrons continuer à lire sans structure OVERLAPPED de poignées qui ont été créés avec le drapeau CHEVAUCHEMENT et poignées qui fuient et les fils ....

Autres conseils

Je vois que je suis un mauvais lecteur de MSDN: / I fonction totalement raté ReOpenFile() qui a été introduit probablement dès 2003 en Juin dans Windows Server 2003 (selon cet article ). Pour me défendre au moins un peu: j'attendre la description de CreateFile() à traverser référence à ReOpenFile() description. Il y a une référence à la page de ReOpenFile() à CreateFile() page, mais pas l'inverse.

Cette fonction semble permettre précisément ce que je dois: ajout ou la suppression de FILE_FLAG_OVELRAPPED à / de poignées déjà existantes en créant de nouvelles poignée avec les propriétés désirées! :-D Je ne l'ai pas encore testé, cependant. Il est, malheureusement, disponible uniquement sur Windows 2003 Server, Windows Vista et les années suivantes. Question sur les versions précédentes du système d'exploitation a été répondu ici . La fonction n'existe pas dans l'API publique dans OS avant Windows 2003 Server. Il est utilisé par la mise en œuvre sous-jacente, mais il n'est pas disponible pour les développeurs sur ces systèmes (non pris en charge).

Cela signifie pratiquement qu'il n'y a pas d'espoir pour moi au moins pour quelques années à venir, jusqu'à ce que nous laissons tomber le soutien pour les plates-formes plus anciennes de Windows. Cela signifie également que la situation en ce qui concerne les E / S a été vraiment mauvais sur OS Windows Vista puis plus. Autre partie douloureuse qui a disparu tout à fait était la possibilité d'annuler E / S synchrones et asynchrones sur les systèmes plus anciens.

De plus, il me manque encore une partie de la réponse: peut la présence de drapeaux testé par tout moyen? Je ne l'ai pas trouvé la fonction pour le faire. Cela signifie que si nous voulons garantir la présence d'un certain drapeau dans l'objet de fichier, le fichier doit toujours être ouvert à nouveau.

Si je comprends ce que vous êtes après, je voudrais suggérer que vous ne vous inquiétez pas si a été ouvert avec le drapeau chevauchée ou non. Je crois que vous pouvez passer en toute sécurité dans une structure OVERLAPPED dans les deux cas synchrones et asynchrones. Votre code doit être capable de gérer ReadFile() retour false et GetLastError() retour ERROR_IO_PENDING. Vous aurez également besoin d'ajouter des appels à GetOverlappedResult() appropriés, WaitForSingleObject(), etc.

L'article MSDN sur ReadFile() a de bonnes informations sur ce sous « Considérations pour travailler avec les descripteurs de fichiers synchrones » et « Considérations pour travailler avec des descripteurs de fichiers asynchrones » dans la section « Synchronisation et position Fichier ».

drapeaux de poignée d'essai devraient probablement faire la même façon que tester les autorisations de la poignée a été créé. Essayez. Si l'API échoue, essayez les solutions de repli. Si cela échoue, renvoie une erreur.

Je pense que la chose vraiment dire est la façon dit la documentation ReadFile « Si hFile est ouvert avec FILE_FLAG_OVERLAPPED, ... fonction peut signaler de manière incorrecte que l'opération de lecture est terminée. »

Mon interprétation de l'erreur est (et la question que vous devez poser vous-même est): s'il était possible de vérifier l'état chevauchée d'un descripteur de fichier, pourquoi ne READFILE pas faire vérifier et valider la structure CHEVAUCHEMENT en conséquence , à l'échec explicitement si elle est appelée d'une manière non chevauché avec une poignée chevauchée?

Je ne sais pas un moyen de déterminer le drapeau d'une poignée et les effets secondaires de l'utilisation ouv api, mais depuis que votre objectif était

  

il serait très utile d'avoir une seule façon de traiter toutes les poignées

Si vous désirez un comportement synchrone (je veux dire à l'aide api synchrone pour les poignées non chevauché et async api alimentée par la structure CHEVAUCHEMENT avec attente après l'événement de chevauché) vous pouvez toujours utiliser le async api même si la poignée a été ouverte en mode non chevauchée comme déjà indiqué par @Brett
Je peux confirmer que cela fonctionne (au moins pour les pipes nommés) es:

void connectSynchronous(HANDLE hPipeThatWeDontKnowItsFlag){
    ...
    BOOL bRet = ::ConnectNamedPipe(hPipeThatWeDontKnowItsFlag, pOverlapped);

    if(bRet == FALSE){
        DWORD dwLastErr = ::GetLastError();

        if(dwLastErr == ERROR_IO_PENDING){
            //The handle was opened for asynchronous IO so we have to wait for the operation
            ...waitFor on the overlapped hEvent;

        }else if(dwLastErr == ERROR_PIPE_CONNECTED){
            //The handle was opened for synchronous IO and the client was already connected before this call: that's OK!
            return;
        }else{
            throw Error(dwLastErr);
        }
    }/*else{
        //The handle was opened for synchronous IO and the client has connected: all OK
    }*/
}

Une alternative au hack CreateIoCompletionPort est de faire un ReadFile zéro octet NULL avec un lpOverlapped. Si elle échoue avec ERROR_INVALID_PARAMETER supposer qu'il a été ouvert avec FILE_FLAG_OVERLAPPED.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top