2011-10-11 4 views
1

Je suis novice en programmation asynchrone. J'ai une DLL C# avec une méthode asynchrone qui est appelée, prend un pointeur de fonction (délégué) et appelle cette fonction de rappel après que "résultat" soit calculé.rappel asynchrone

public delegate void CreatedDelegate(Foo result); 

public void CreateAsync(CreatedDelegate createdCallback) 
    { 
     Task t = Task.Factory.StartNew(() => 
             { 
             Foo result = ... 
             createdCallback(result); 
             }); 
    } 

Le rappel de délégué de type « CreatedDelegate » est (dans mon cas) un pointeur de fonction à un procédé de C++/CLI qui fonctionne avec le résultat. Donc, ce concept asynchrone semble assez bien fonctionner dans la plupart des cas, mais parfois je rencontre quelques erreurs. Comment puis-je y arriver si la fonction "CreateAsync" est appelée plusieurs fois avec des efforts de calcul différents, que les appels résultants à "CreatedCallback" se produisent dans le même ordre que l'original "CreateAsync" a été appelé? Pour le rendre plus clair: Le premier appel à "CreateAsync" devrait aboutir au premier appel à "CreatedCallback" même si un appel suivant de "CreateAsync" est plus rapide et appelait le callback plus tôt.

Peut-être que cela peut être fait en autorisant un seul nouveau thread actif dans le "CreateAsync" asynchrone à la fois?

+0

Ce n'est pas, comment fonctionne filetage à partir de plus d'un et les ayant complète hors de manière imprévisible est de par sa conception. Utilisez un modèle producteur/consommateur si c'est un problème. –

Répondre

1

Pour traiter les callbacks dans l'ordre, vous aurez besoin de mettre en œuvre certaines des files d'attente des éléments de travail. Le moyen le plus simple est probablement d'utiliser le type BlockingCollection (voir MSDN documentation).

Au lieu d'appeler la fonction de rappel, votre méthode CreateAsync ajouter la tâche (en même temps que le rappel) à la file d'attente:

// Queue to keep tasks and their callbacks 
private BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>> 
    queue = new BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>() 

public void CreateAsync(CreatedDelegate createdCallback) { 
    Task<Foo> t = Task.Factory.StartNew(() => { 
     Foo result = ... 
     return result; }); 
    queue.Add(Tuple.Create(t, createdCallback)); 
    // .. 
} 

Cela ajoutera que des tâches et callbacks à la file d'attente - d'appeler en fait le rappel , vous aurez besoin d'une autre tâche qui attend les tâches dans la file d'attente (dans l'ordre dans lequel ils ont été ajoutés) et appelle le rappel:

Task.Factory.StartNew(() => { 
    while(true) { // while you keep calling 'CreateAsync' 
    // Get next task (in order) and its callback 
    Tuple<Task<Foo>, CreatedDelegate> op = queue.Take(); 
    // Wait for the result and give it to callback 
    op.Item2(op.Item1.Result); 
    } 
} 
+0

Thx, je vais essayer ça bientôt. – Michbeckable

0

Si l'ordre est important, alors l'aide de fils peut-être mieux:

thread queue = empty 
for each task 
{ 
    if there are no free 'cpu' 
    wait on first thread in queue 
    remove thread from queue 
    call delegate 

    create thread 
    add thread to queue 
} 

while queue has threads 
    wait on first thread in queue 
    remove thread from queue 
    call delegate 
+0

Thx, cela pourrait être le point. Est-ce à intégrer dans le "CreateAsync" se débarrasser de la Task.Factory.StartNew ...? – Michbeckable

+0

Votre CreateAsync est le bit "créer un thread/ajouter à la file d'attente". – Skizz

Questions connexes