> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Modèle de programmation asynchrone

> Modèle de programmation asynchrone

Le Microsoft Game Development Kit (GDK) implémente un nouveau modèle pour les API asynchrones qui
répond aux commentaires que nous avons reçus des développeurs de jeux vidéo concernant
le modèle asynchrone implémenté dans le cadre du modèle de programmation ERA de la XBOX One.
Notre objectif est que ce nouveau modèle soit beaucoup plus facile à intégrer dans
les architectures de jeu typiques et qu'il offre aux développeurs de jeux vidéo le haut niveau de
contrôle qu'ils ont demandé. Cette rubrique décrit ce modèle de
conception et propose une bibliothèque pouvant être utilisée pour
implémenter des modèles asynchrones.

<a id="gdk_asynchronous_model" />

## Modèle conceptuel

La programmation asynchrone dans le Microsoft Game Development Kit (GDK) se divise en 2 composants principaux :
les tâches et les files d'attente de tâches. Bien que les bibliothèques offrent davantage de
fonctionnalités, l'ensemble du modèle conceptuel repose sur ces 2 composants principaux.

Une tâche est un ensemble unique de travail asynchrone qui peut être démarré, dont l'état
peut être vérifié, qui peut éventuellement être annulé, qui se termine et qui retourne ses
informations d'achèvement. Dans le modèle du Microsoft Game Development Kit (GDK), les tâches sont composées de deux
corps : le rappel de travail et le rappel d'achèvement. Cela permet
un plus grand contrôle, par exemple un traitement entièrement parallèle ou un travail parallèle combiné
à un achèvement sur un seul thread.

Une file d'attente de tâches est un conteneur qui met en file d'attente les rappels de travail et
d'achèvement en vue d'une exécution ultérieure. Une file d'attente de tâches comporte deux files
internes, appelées ports, qui gèrent séparément les rappels de travail et d'achèvement.
Il s'agit du port de travail et du port d'achèvement.

**Figure 1.  Diagramme d'une tâche et d'une file d'attente de tâches**

<img src="https://mintcdn.com/microsoft-4404708b/sIrPFR_ir_sNKVEv/images/gdk/features/common/async_task_taskqueue_diagram.png?fit=max&auto=format&n=sIrPFR_ir_sNKVEv&q=85&s=89181466bdb096dbacd570ff0f1dcac5" alt="Diagramme d'une tâche et d'une file d'attente de tâches." width="660" height="314" data-path="images/gdk/features/common/async_task_taskqueue_diagram.png" />

Chaque port de la file d'attente de tâches est configuré différemment [au moment de la
création](/fr-CA/reference/system/xtaskqueue/functions/xtaskqueuecreate) afin de créer des comportements d'exécution des rappels différents. Par
exemple, le port de travail peut être configuré pour être asynchrone et le
port d'achèvement peut être configuré pour s'exécuter en série sur un thread principal. Un
paramètre manuel peut être défini pour permettre un contrôle complet du comportement
d'exécution. Les modes de configuration des ports sont [expliqués plus loin](#controlling_work_dispatching).

Lorsqu'une tâche asynchrone est démarrée, les rappels ne sont pas mis immédiatement dans la
file d'attente de tâches. Un [fournisseur asynchrone](/fr-CA/build/core-features/common/async/async-libraries/async-library-xasyncprovider)
gère les changements d'état pour s'assurer que le travail est mis en file d'attente et distribué
avant que le rappel d'achèvement soit mis en file d'attente et distribué.

La file d'attente de tâches ne gère pas directement les threads elle-même. Elle
s'appuie plutôt sur un appel externe pour [distribuer](/fr-CA/reference/system/xtaskqueue/functions/xtaskqueuedispatch) ses ports. Les
appels externes déterminent le comportement en matière de threads et de concurrence. La
file d'attente de tâches elle-même est entièrement thread-safe.

**Figure 2.  Port distribué sur plusieurs threads**

<img src="https://mintcdn.com/microsoft-4404708b/sIrPFR_ir_sNKVEv/images/gdk/features/common/async_port_dispatch_multithread.png?fit=max&auto=format&n=sIrPFR_ir_sNKVEv&q=85&s=697aae48e97cb3aa23845108060a1882" alt="Image montrant un port distribué sur plusieurs threads." width="628" height="230" data-path="images/gdk/features/common/async_port_dispatch_multithread.png" />

Et c'est essentiellement tout! Les rappels d'une tâche sont mis en file d'attente dans les ports
de travail et d'achèvement d'une file d'attente de tâches, et cette file d'attente fait distribuer ces
rappels d'une certaine manière. L'API contient toute une suite de
fonctionnalités pour gérer les files d'attente de tâches, vérifier l'état des rappels, suivre
les données de travail, créer une gestion de tâches personnalisée, et plus encore.

Les appels d'API asynchrones du Microsoft Game Development Kit (GDK) implémentent toujours le rappel de travail en interne,
et les rappels d'achèvement sont toujours facultatifs. Pour une utilisation au-delà des appels asynchrones du Microsoft Game Development Kit (GDK),
vous devez fournir le rappel de travail.

## Exigences

Les développeurs de jeux vidéo ont énuméré les exigences suivantes pour les appels d'API.

1. Privilégier les appels synchrones plutôt que les appels asynchrones
2. Offrir l'asynchronisme avec interrogation
3. Offrir l'asynchronisme avec rappels
4. Offrir le contrôle du thread sur lequel le travail asynchrone s'exécute
5. Offrir le contrôle du thread sur lequel les rappels d'achèvement
   s'exécutent

## Types d'API

Le Microsoft Game Development Kit (GDK) s'efforce d'être très simple dans la conception
de ses API. Les développeurs de jeux vidéo sont des experts dans l'optimisation de leur code pour
tirer le meilleur parti du matériel. Nous leur donnons le contrôle chaque fois que
c'est possible. Les implémentations d'API se répartissent dans les types suivants.

* **Sécuritaire en contexte critique :** Une API sécuritaire en contexte critique est une API qui peut
  être appelée sur un thread critique en matière de temps. Notez que, même si cela
  signifie généralement que l'API est triviale ou très rapide, le concept clé est que les
  caractéristiques de performance de l'API sont *constantes*. Ces API
  sont toujours synchrones et n'ont jamais besoin d'une version
  asynchrone. Ces API doivent être documentées comme étant sécuritaires en contexte critique.

* **Non sécuritaire en contexte critique :** Ces API ne peuvent pas être appelées en toute sécurité à partir
  du thread de rendu. Leurs caractéristiques de performance peuvent varier
  considérablement. La plupart des API entrent dans cette catégorie.

* **Asynchrone :** Ces API sont asynchrones par nature, comme un
  appel de service Web. Elles utilisent le modèle asynchrone décrit dans
  cette rubrique. Les API asynchrones sont moins courantes dans le Microsoft Game Development Kit (GDK) que dans le modèle de programmation ERA de la XBOX One : une API
  asynchrone est généralement de longue durée et annulable. Sauf dans quelques
  cas d'utilisation précis, les API asynchrones disposent d'une
  version synchrone non sécuritaire en contexte critique. L'appel d'une API
  asynchrone doit toujours être sécuritaire en contexte critique.

* **Notifications :** Les notifications sont de nature périodique et n'ont pas de
  fin définie. Elles sont liées aux API asynchrones, mais en raison de
  leur nature périodique, elles doivent avoir une apparence et un comportement différents pour
  les développeurs. L'inscription à une notification doit toujours être
  sécuritaire en contexte critique.

## Modèle d'API asynchrone

Le Microsoft Game Development Kit (GDK) introduit un modèle d'API asynchrone à usage général que les composants du Microsoft Game Development Kit (GDK) peuvent utiliser pour offrir une prise en charge asynchrone cohérente. Au
cœur de ce modèle se trouve une structure semblable à OVERLAPPED, appelée [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) :

```c++ theme={null}
typedef void CALLBACK XAsyncCompletionRoutine(struct XAsyncBlock* asyncBlock);

struct XAsyncBlock
{
    XTaskQueueHandle queue;
    void* context;
    XAsyncCompletionRoutine* callback;
    unsigned char internal[sizeof(void*) * 4];
};
```

Un [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) est une structure fournie par l'appelant. L'appelant remplit les
champs facultatifs de cette structure, comme le montre le tableau suivant.

| Champ | Description |
| - | - |
| **queue** | Un handle de file d'attente de tâches qui peut contrôler les threads qui exécutent l'appel asynchrone. Si ce paramètre est null, la file d'attente de tâches du processus est utilisée. Si la file d'attente de tâches du processus a été définie sur null, l'appel échoue avec E\_NO\_TASK\_QUEUE. |
| **context** | Un pointeur de contexte facultatif qui est passé à la fonction de rappel. |
| **callback** | Une fonction de rappel facultative qui est appelée lorsque l'opération est terminée. |

Les champs **Internal** sont utilisés par le système et ne doivent pas être modifiés.
Les champs de cette structure définissables par l'utilisateur ne doivent pas être modifiés
pendant une opération asynchrone. Un [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) doit rester en mémoire pendant toute la
durée de vie de l'opération asynchrone. Si le [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) est alloué dynamiquement,
le rappel d'achèvement est le moment le plus tôt où il peut être supprimé.

En plus de [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock), il existe un petit nombre d'API d'assistance, présentées ci-dessous.

```c++ theme={null}
STDAPI XAsyncGetStatus(XAsyncBlock* asyncBlock, bool wait);

STDAPI XAsyncGetResultSize(XAsyncBlock* asyncBlock, size_t* bufferSize);

STDAPI_(void) XAsyncCancel(XAsyncBlock* asyncBlock);

typedef HRESULT CALLBACK XAsyncWork(XAsyncBlock* asyncBlock);

STDAPI XAsyncRun(XAsyncBlock* asyncBlock, XAsyncWork* work);
```

[XAsyncGetStatus](/fr-CA/reference/system/xasync/functions/xasyncgetstatus) retourne l'état d'un appel asynchrone. Lorsque
l'appel commence, cet état est E\_PENDING. Il passe à S\_OK ou à une
erreur précise une fois l'appel terminé. Si l'appel est annulé, cette fonction retourne
E\_ABORT.

[XAsyncGetResultSize](/fr-CA/reference/system/xasync/functions/xasyncgetresultsize) retourne la taille de mémoire tampon requise pour obtenir les
résultats de l'appel. L'API réelle qui récupère les résultats est adaptée à
chaque appel asynchrone.

[XAsyncCancel](/fr-CA/reference/system/xasync/functions/xasynccancel) peut être utilisée pour annuler un appel. L'annulation dépend de l'opération annulée et peut se produire de façon synchrone, asynchrone ou pas du tout. Si une opération est annulée,
[XAsyncGetResult](/fr-CA/reference/system/xasyncprovider/functions/xasyncgetresult), [XAsyncGetResultSize](/fr-CA/reference/system/xasync/functions/xasyncgetresultsize) ou [XAsyncGetStatus](/fr-CA/reference/system/xasync/functions/xasyncgetstatus) retournent E\_ABORT. Un appel
annulé signale le paramètre [XAsyncCompletionRoutine](/fr-CA/reference/system/xasync/functions/xasynccompletionroutine) du [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) et appelle son
rappel.

[XAsyncRun](/fr-CA/reference/system/xasync/functions/xasyncrun) est une méthode d'assistance qui peut exécuter n'importe quel code de façon asynchrone.

### Utilisation des API asynchrones

Examinons d'abord une API synchrone dans l'exemple de code suivant.

```c++ theme={null}
HRESULT XGameSaveGetRemainingQuota(XGameSaveProviderHandle provider,
int64_t* remainingQuota);
```

Cette API appelle un service Web pour déterminer la quantité de stockage de sauvegarde de jeu
encore disponible. Pour ajouter la prise en charge asynchrone, nous déclarons une paire de nouvelles
API.

```c++ theme={null}
HRESULT XGameSaveGetRemainingQuotaAsync(XGameSaveProviderHandle
provider, XAsyncBlock* async);

HRESULT XGameSaveGetRemainingQuotaResult(XAsyncBlock* async,
int64_t* remainingQuota);
```

[XGameSaveGetRemainingQuotaAsync](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaasync) retourne S\_OK si l'appel asynchrone a été
lancé (comme cette API est uniquement asynchrone, il n'y a aucun intérêt à retourner
E\_PENDING). [XGameSaveGetRemainingQuotaResult](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaresult) retourne E\_PENDING
jusqu'à ce que l'appel soit terminé.

Voyons comment cela fonctionne en pratique.

```c++ theme={null}
// providerHandle is a previously obtained XGameSaveProviderHandle.

XAsyncBlock* b = new XAsyncBlock;
ZeroMemory(b, sizeof(XAsyncBlock));
b->context = this;
b->queue = queue;
b->callback = [](XAsyncBlock* async)
{
    int64_t remainingQuota;
    if(SUCCEEDED(XGameSaveGetRemainingQuotaResult(async, &remainingQuota)))
    {
        printf("Remaining quota: %irn", remainingQuota);
    }
    delete async;
};
XGameSaveGetRemainingQuotaAsync(providerHandle, b);
```

Les [XAsyncBlocks](/fr-CA/reference/system/xasync/structs/xasyncblock) nécessitent tous une file d'attente de tâches (décrite ci-dessous), qui contrôle
où et comment l'appel asynchrone est exécuté. Une file d'attente de tâches à l'échelle du processus
est utilisée si aucune n'est fournie.

Notez que le [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) doit rester en mémoire pendant toute la durée de
l'appel asynchrone. Dans cet exemple, il a été alloué dynamiquement et supprimé dans
le rappel d'achèvement. Il pourrait également être stocké sous forme de variable globale ou de variable
membre. Un comportement indéfini se produit si le même [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) est utilisé pour
plus d'un appel asynchrone à la fois.

[XGameSaveGetRemainingQuotaResult](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaresult) termine le cycle d'un appel asynchrone.
Elle libère les données internes du bloc asynchrone, de sorte que le bloc peut maintenant être
utilisé pour un nouvel appel. Les appels subséquents à
[XGameSaveGetRemainingQuotaResult](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaresult) échouent.
[XGameSaveGetRemainingQuotaAsync](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaasync) et [XGameSaveGetRemainingQuotaResult](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaresult) sont
également associées dans le bloc asynchrone : une erreur se produit si vous
associez un appel asynchrone à une autre API de résultat.

Si un appel asynchrone n'a aucune charge utile de données, c'est-à-dire que seul l'état HRESULT est
important, définissez une méthode **Result** qui prend uniquement le bloc asynchrone, comme suit.

```c++ theme={null}
HRESULT QueryUpdateStatusAsyncResult(_Inout_ XAsyncBlock* block);
```

<a id="controlling_work_dispatching" />

### Contrôle de la distribution du travail

Quel thread a effectué le travail asynchrone dans les appels précédents? Quel thread a appelé
le rappel d'achèvement? C'est la file d'attente de tâches affectée au
[XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock) qui en décide.

Les files d'attente de tâches ont deux « ports » : un *port de travail* et un *port d'achèvement*. Chaque
port possède un mode de distribution qui détermine la façon dont les rappels mis en file d'attente sur un port
sont traités. Il existe plusieurs modes de distribution.

* **Pool de threads :** Les rappels mis dans une file d'attente de pool de threads sont
  exécutés sur le pool de threads du système. Le pool de threads appelle les
  rappels en parallèle, en prenant tour à tour un appel à exécuter dans la file d'attente
  à mesure que des threads du pool deviennent disponibles.

* **Pool de threads sérialisé :** Les rappels sont mis en file d'attente et exécutés sur le
  pool de threads, mais un à la fois.

* **Manuel :** Les rappels mis dans une file d'attente manuelle ne sont pas automatiquement
  distribués. Il revient au développeur de les distribuer sur le thread
  de son choix.

* **Immédiat :** Le mode de distribution immédiat n'effectue aucune mise en file d'attente. Il
  exécute immédiatement l'appel sur le thread qui a soumis le
  rappel.

Une file d'attente de tâches de processus par défaut est configurée de sorte que les ports de travail
et les ports d'achèvement soient distribués par l'intermédiaire du pool de threads du système. Cette
file d'attente de tâches de processus est utilisée si aucun paramètre de file d'attente n'est passé dans le
[XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock). Un jeu peut également désactiver la file d'attente de tâches du processus, ce qui exige qu'une
file d'attente soit passée dans le [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock).

Nous nous attendons à ce que de nombreux développeurs choisissent le mode de distribution manuel pour
exercer un contrôle complet sur le moment et l'endroit où s'exécutent le travail asynchrone et les rappels
d'achèvement.

Pour plus de détails sur les files d'attente de tâches, consultez [Conception de la file d'attente de tâches asynchrones](/fr-CA/build/core-features/common/async/async-task-queue-design).

## Notifications

Une notification peut ne pas avoir de fin et peut être appelée de nombreuses fois.
Les notifications doivent prendre en charge un sous-ensemble des exigences d'un appel
asynchrone.

1. Asynchronisme avec interrogation
2. Asynchronisme avec rappels
3. Contrôle du thread sur lequel les rappels se produisent

Les notifications utilisent une file d'attente de tâches pour permettre au développeur de contrôler
le thread de rappel, mais n'utilisent pas de blocs asynchrones par ailleurs : elles sont
conçues pour ressembler davantage à des événements standard avec des méthodes **Register** et **Unregister**.

* Une méthode **Register** qui prend tous les paramètres propres à l'appel, une file d'attente
  de tâches, un contexte void facultatif et un pointeur de rappel fortement
  typé. Le dernier paramètre est un paramètre *out* qui
  retourne un jeton.

* Une méthode **Unregister** qui prend tout contexte propre à l'appel et le
  jeton.

* L'interrogation est prise en charge par l'ajout d'une méthode distincte qui n'est pas liée au
  rappel de notification.

Examinons l'exemple suivant, qui pourrait récupérer des messages Windows.

```c++ theme={null}
struct XTaskQueueRegistrationToken;

typedef void MessageAvailableCallback(void* context, const MSG* msg);

HRESULT RegisterMessageAvailable(
    XTaskQueueHandle queue,
    void* context,
    MessageAvailableCallback* callback,
    XTaskQueueRegistrationToken * token);

bool UnregisterMessageAvailable(XTaskQueueRegistrationToken token, bool
wait);

// Usage.
XTaskQueueRegistrationToken token;
RegisterMessageAvailable(queue, nullptr, [](void*, const MSG* msg)
{
    printf("Message: %drn", msg->message);
}, &token);
```

Notez que, dans cet exemple, **UnregisterMessageAvailable** prend un dernier
paramètre « wait » et retourne un bool. Cela permet aux appelants de décider comment
gérer l'annulation de l'inscription pendant qu'un appel est en cours.

<a id="heading-7" />

## Bibliothèque asynchrone

Pour faciliter la création d'API cohérentes qui prennent en charge le modèle
asynchrone, nous fournissons une bibliothèque qui peut être utilisée pour implémenter la « plomberie
asynchrone » d'une API. L'API de la bibliothèque se présente comme suit.

```c++ theme={null}
enum class XAsyncOp : uint32_t
{
    Begin,
    DoWork,
    GetResult,
    Cancel,
    Cleanup
};

struct XAsyncProviderData
{
    XAsyncBlock* async;  
    size_t bufferSize;  
    void* buffer;  
    void* context;
};

typedef HRESULT CALLBACK XAsyncProvider(
_In_ XAsyncOp op,
_Inout_ XAsyncProviderData* data);

STDAPI XAsyncBegin (
_Inout_ XAsyncBlock* asyncBlock,
_In_opt_ void* context,
_In_opt_ void* identity,
_In_opt_ const char* identityName,
_In_ XAsyncProvider* provider);

STDAPI XAsyncSchedule(
_Inout_ XAsyncBlock* asyncBlock,
_In_ uint32_t delayInMs);

STDAPI_(void) XAsyncComplete(
_Inout_ XAsyncBlock* asyncBlock,
_In_ HRESULT result,
_In_ size_t requiredBufferSize);

STDAPI XAsyncGetResult(
_Inout_ XAsyncBlock* asyncBlock,
_In_opt_ void* identity,
_In_ size_t bufferSize,
_Out_writes_bytes_opt_(bufferSize) void* buffer,
_Out_opt_ size_t* bufferUsed);
```

Cette API utilise un seul rappel, combiné à une valeur d'opération qui
indique pourquoi l'API est appelée. Il existe également une seule structure
de données qui est remplie à mesure que l'appel progresse. Pour utiliser cette API,
procédez comme suit.

1. Appelez [XAsyncBegin](/fr-CA/reference/system/xasyncprovider/functions/xasyncbegin) avec le bloc asynchrone passé par l'appelant, et
   fournissez un rappel qui fournit l'implémentation.

2. Effectuez le travail asynchrone de l'appel. Si vous devez exécuter le travail sur
   un thread de travail, appelez [XAsyncSchedule](/fr-CA/reference/system/xasyncprovider/functions/xasyncschedule). Si vous pouvez effectuer le travail en
   utilisant des primitives asynchrones du système d'exploitation et configurer ces primitives assez rapidement pour
   demeurer sécuritaire en contexte critique, cette approche est à privilégier.

3. Si vous devez appeler un autre travail asynchrone à partir d'un rappel de thread
   de travail, vous pouvez retourner E\_PENDING à partir du thread de travail. Vous pouvez également
   appeler [XAsyncSchedule](/fr-CA/reference/system/xasyncprovider/functions/xasyncschedule) à partir d'un thread de travail pour replanifier du
   travail supplémentaire.

4. Lorsque tout le travail est terminé, appelez [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete).

5. Fournissez un wrapper fortement typé autour de [XAsyncGetResult](/fr-CA/reference/system/xasyncprovider/functions/xasyncgetresult) pour retourner
   les résultats.

6. Si votre appel asynchrone n'a aucune charge utile de données, vous devez fournir un wrapper
   fortement typé autour de [XAsyncGetStatus](/fr-CA/reference/system/xasync/functions/xasyncgetstatus) et passer zéro comme taille de mémoire
   tampon requise à [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete).

Le rappel du fournisseur asynchrone est appelé avec les
opérations suivantes.

* **Begin** Un fournisseur asynchrone est appelé avec ce code d'opération pendant [XAsyncBegin](/fr-CA/reference/system/xasyncprovider/functions/xasyncbegin). Si le fournisseur implémente ce code d'opération, il doit démarrer sa tâche asynchrone en appelant [XAsyncSchedule](/fr-CA/reference/system/xasyncprovider/functions/xasyncschedule) ou par des moyens externes. Ce rappel est appelé de façon synchrone dans la chaîne d'appels de [XAsyncBegin](/fr-CA/reference/system/xasyncprovider/functions/xasyncbegin); il ne doit donc jamais bloquer.

* **DoWork** Appelé dans les cas où [XAsyncSchedule](/fr-CA/reference/system/xasyncprovider/functions/xasyncschedule) a été appelée pour
  planifier un travail asynchrone au moyen de la file d'attente de tâches. La fonction du fournisseur effectue
  tout le travail nécessaire. Une fois terminé, elle appelle [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete) avec le
  code de résultat et la taille de la charge utile de données, qui peut être zéro si l'appel n'a
  aucune charge utile de données. Si d'autres travaux asynchrones doivent être
  effectués, le fournisseur peut planifier ce travail et doit retourner
  E\_PENDING.

* **GetResult** Appelé pour récupérer le résultat de l'appel. Comme la
  taille des données est passée à [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete) lors de l'achèvement de l'appel, aucune
  vérification des arguments n'est nécessaire ici : toutes les mémoires tampons et leurs tailles
  ont été vérifiées par la bibliothèque.

* **Cancel** Appelé lorsque l'utilisateur annule un appel asynchrone. Si l'appel peut être annulé, annulez-le et appelez [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete) avec E\_ABORT comme code de résultat.

* **Cleanup** Appelé lorsque l'appel est complètement terminé et que le
  fournisseur peut supprimer toute mémoire dynamique.

Un fournisseur asynchrone n'a besoin d'implémenter que les opérations dont il a besoin. Par
exemple, une E/S asynchrone non annulable qui ne nécessite aucun nettoyage n'a besoin
d'implémenter que **GetResult**.

Voici un exemple d'une méthode **FactorialAsync** qui calcule une factorielle
de façon asynchrone.

```c++ theme={null}
UINT64 Factorial(UINT64 value)
{
    UINT64 result = 1;

    while (value != 0)
    {       
        result *= value;
        value--;
    }

    return result;
}

HRESULT FactorialAsync(UINT64 value, XAsyncBlock* async)
{
    struct CallData
    {
        UINT64 value;
        UINT64 result;
    };

    CallData* data = new CallData();
    data->value = value;
    data->result = 1;

    HRESULT hr = XAsyncBegin (async, data, FactorialAsync, __FUNCTION__, []
        (XAsyncOp op, XAsyncProviderData* data)
    {
        CallData* d = (CallData*)data->context;

        switch (op)
        {
        case XAsyncOp::Begin:
            return XAsyncSchedule(data->async, 0);

        case XAsyncOp::Cleanup:
            delete d;
            break;

        case XAsyncOp::GetResult:
            CopyMemory(data->buffer, &d->result, sizeof(UINT64));
            break;
 
        case XAsyncOp::DoWork:
            data->result = Factorial(data.Value);
            XAsyncComplete(data->async, S_OK, sizeof(UINT64));
            break;
        }

        return S_OK;
    });

    return hr;
}

HRESULT FactorialAsyncResult(XAsyncBlock* async, UINT64* result)
{
    return XAsyncGetResult(async, FactorialAsync, sizeof(UINT64), result);
}
```

## Documentation de référence de l'API

* [XAsync (contenu de l'API)](/fr-CA/reference/system/xasync/xasync_members)
  * Fonctions
    * [XAsyncGetStatus](/fr-CA/reference/system/xasync/functions/xasyncgetstatus)
    * [XAsyncGetResultSize](/fr-CA/reference/system/xasync/functions/xasyncgetresultsize)
    * [XAsyncCancel](/fr-CA/reference/system/xasync/functions/xasynccancel)
    * [XAsyncCompletionRoutine](/fr-CA/reference/system/xasync/functions/xasynccompletionroutine)
    * [XAsyncRun](/fr-CA/reference/system/xasync/functions/xasyncrun)
  * Structures
    * [XAsyncBlock](/fr-CA/reference/system/xasync/structs/xasyncblock)
* [XAsyncProvider (contenu de l'API)](/fr-CA/reference/system/xasyncprovider/xasyncprovider_members)
  * Fonctions
    * [XAsyncGetResult](/fr-CA/reference/system/xasyncprovider/functions/xasyncgetresult)
    * [XAsyncBegin](/fr-CA/reference/system/xasyncprovider/functions/xasyncbegin)
    * [XAsyncSchedule](/fr-CA/reference/system/xasyncprovider/functions/xasyncschedule)
    * [XAsyncComplete](/fr-CA/reference/system/xasyncprovider/functions/xasynccomplete)
* [XTaskQueue (contenu de l'API)](/fr-CA/reference/system/xtaskqueue/xtaskqueue_members)
  * Fonctions
    * [xtaskqueuecreate](/fr-CA/reference/system/xtaskqueue/functions/xtaskqueuecreate)
    * [xtaskqueuedispatch](/fr-CA/reference/system/xtaskqueue/functions/xtaskqueuedispatch)
* [xgamesave (contenu de l'API)](/fr-CA/reference/system/xgamesave/xgamesave_members)
  * Fonctions
    * [XGameSaveGetRemainingQuotaAsync](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaasync)
    * [XGameSaveGetRemainingQuotaResult](/fr-CA/reference/system/xgamesave/functions/xgamesavegetremainingquotaresult)

## Voir aussi

[Objectifs de conception et améliorations de la programmation asynchrone](/fr-CA/build/core-features/common/async/async-whitepaper)
[Conception de la file d'attente de tâches asynchrones](/fr-CA/build/core-features/common/async/async-task-queue-design)


## Related topics

- [Guide de programmation Direct3D 12](/fr-CA/build/gdk-and-engines/guides/directx-12-programming-guide.md)
- [Documentation de développement de jeux XBOX](/fr-CA/index.md)
- [Guides de portage vers le GDK XBOX](/fr/home/build-first-title/porting-guides.md)
- [Guides de portage vers le XBOX GDK](/fr-CA/home/build-first-title/porting-guides.md)
- [Porter depuis une génération XBOX antérieure](/fr-CA/paths/porting/from-xbox-era.md)
