La réponse d'Andreas Huber à this question m'a donné une idée pour implémenter Concurrent<T>
avec des délégués asynchrones au lieu du ThreadPool. Cependant, je trouve qu'il est plus difficile de comprendre ce qui se passe lorsqu'un AsyncCallback
est passé à BeginInvoke
, en particulier lorsque plusieurs threads ont accès à IAsyncResult
. Malheureusement, ce cas ne semble pas être couvert à MSDN ou n'importe où je pourrais trouver. De plus, tous les articles que j'ai pu trouver étaient écrits avant les fermetures et les génériques étaient disponibles ou semblaient juste comme ça. Il y a plusieurs questions (et les réponses que j'espère sont vraies, mais je suis prêt à être déçu):Utilisation de BeginInvoke/EndInvoke dans un mode multithread. Comment AsyncCallback, AsyncWaitHandle et IsCompleted interagissent-ils?
1) L'utilisation d'une fermeture comme AsyncCallback ferait-elle une différence?
(pas un peu de chance)
2) Si un thread attend sur le AsyncWaitHandle
, qu'il sera signalaient
a) avant que le rappel commence ou b) après la fin?
(Espérons que b)
3) Pendant que le rappel est en cours, que retournera IsCompleted
? Possibilités que je peux voir:
a) true
; b) false
; c) false
avant que le rappel appelle EndInvoke, true
après.
(Espérons que b ou c)
4) Est-ce que DisposedObjectException
sera lancé si un thread attend le AsyncWaitHandle
après EndInvoke
?
(J'espère que non, mais je m'attends à oui).
à condition que les réponses sont comme je l'espère, cela semble que cela devrait fonctionner:
public class Concurrent<T> {
private IAsyncResult _asyncResult;
private T _result;
public Concurrent(Func<T> f) { // Assume f doesn't throw exceptions
_asyncResult = f.BeginInvoke(
asyncResult => {
// Assume assignment of T is atomic
_result = f.EndInvoke(asyncResult);
}, null);
}
public T Result {
get {
if (!_asyncResult.IsCompleted)
// Is there a race condition here?
_asyncResult.AsyncWaitHandle.WaitOne();
return _result; // Assume reading of T is atomic
}
...
Si les réponses aux questions 1-3 sont ceux que j'espérer, il devrait y avoir aucune condition de raace ici, d'aussi loin que je puisse voir.
Alors que vos réponses seraient très applicables si je voulais implémenter IAsyncResult ici, je ne le fais pas. Je pose la question sur le comportement de System.Runtime.Remoting.Messaging.AsyncResult, celui effectivement retourné par BeginInvoke. –
Question 1: C'est précisément ce que je voulais dire par "Malheureusement, ce cas ne semble pas être couvert à MSDN ou n'importe où je pourrais trouver." Je n'expose pas _asyncResult directement, mais seulement en attendant dans la propriété Result; mais les implémentations dans le cadre ne le font même pas. –
Question 2: Bon, c'est ce que j'espérais. –