Comment ouvrir un fichier dans Windows de manière asynchrone

Est-il possible d’ouvrir un fichier sous Windows de manière asynchrone? La fonction API CreateFile a uniquement FILE_FLAG_OVERLAPPED qui permet d’autres lectures et écritures asynchrones. Néanmoins, l’ouverture du fichier semble être synchrone. Étant donné qu’il doit accéder au système de fichiers (et potentiellement effectuer des opérations IO coûteuses), il peut être un bloqueur potentiel.

C’est en fait une question sous-jacente à savoir s’il est possible d’ouvrir un fichier en .NET de manière asynchrone (car FileStream ctor ne peut pas être attendu). Mais la question est plutôt inutile s’il n’y a aucun moyen de le faire dans le système d’exploitation.

Malheureusement, le mode utilisateur ne permet pas de créer / ouvrir un fichier de manière asynchrone. Même si le pilote retourne STATUS_PENDING pour IRP_MJ_CREATE , le système attend dans ce cas jusqu’à ce que le pilote termine l’ IRP avant de retourner le contrôle de l’une des fonctions de création / ouverture de fichier.

Seulement si nous sums en mode kernel, il est possible, si vous formatez vous-même IRP_MJ_CREATE et envoyez-le au pilote. Mais même dans ce cas, les pilotes IRP_MJ_CREATE presque toujours IRP_MJ_CREATE synchrone.


pour API être asynchrone – doit être un moyen de notifier l’appelant lorsque l’opération est terminée

windows utilisé 3 façons pour cela

  1. une routine de rappel dans les parameters, généralement APC ( PIO_APC_ROUTINE ) qui a appelé lorsque l’opération s’est terminée
  2. certains événements dans les parameters, lorsque l’opération est terminée, événement défini dans l’état du signal.
  3. Le descripteur de fichier, utilisé dans l’appel api, est lié à certains IOCP. lorsque l’opération paquet terminé est mis en queue à IOCP. (nous GetQueuedCompletionStatus ce paquet plus tard en appelant GetQueuedCompletionStatus ( ZwRemoveIoCompletion ) ou KeRemoveQueue

3) est impossible dans notre cas parce que le descripteur de fichier n’a pas encore été créé, il ne peut donc être lié à aucun IOCP. environ 1) et 2) laisser rechercher des fichiers ouvrir / créer des signatures api:

en mode utilisateur, le niveau le plus bas pour ouvrir / créer un fichier est ZwOpenFile et ZwCreateFile . CreateFile est un shell sur ZwCreateFile . en mode kernel NtOpenFile -> NtCreateFile -> IoCreateFile -> IoCreateFileEx pair – IoCreateFileEx (l’API de niveau le plus bas pour créer un fichier) – n’a aucun paramètre de rappel Event ou [Apc] – donc pas asynchrone. IoCreateFileEx appelle ObOpenObjectByName (pas documenté, mais exporté routine) – ici aussi pas 1) ou 2) parameters – encore une fois, ceci est synchrone par api de conception

Est-il possible d’ouvrir un fichier sous Windows de manière asynchrone?

Non malheureusement. Fait intéressant, au niveau du pilote de périphérique, toute interaction de ce type est asynchrone (ou peut au moins être asynchrone). Mais cela n’est pas exposé au niveau Win32.

Les API d’ouverture de fichiers asynchrones UWP ne sont que de fausses API asynchrones: elles délèguent le travail synchrone au pool de threads. Ils ne sont pas vraiment asynchrones. Vous devrez faire la même chose si vous voulez ouvrir les fichiers sans blocage sur .NET (ce qui est souvent souhaitable si vous traitez des fichiers sur un partage réseau).

Malheureusement, le mécanisme CreateFile regroupe le concept de création du handle avec le concept de l’associer à un fichier nommé sur un disque quelque part.

alors qu’avec les sockets, vous appelez une fonction pour créer un handle de socket, puis l’associez (liez-la) à un noeud final (en fait un nom).

MS aurait pu faire quelque chose de similaire pour les fichiers, où vous alloueriez d’abord le handle non lié, puis l’associez à un port d’achèvement, puis demandez de manière asynchrone l’association avec un chemin de fichier, qui pourrait ensuite être signalé à la fin.

Car face à cela, tous les éléments du redirecteur réseau sont asynchrones, et toute la gestion des IRP par le gestionnaire IO l’est également.

Il est fou qu’après 30 ans, il n’y a toujours aucun moyen de le faire dans Windows.