2009-01-14 12 views
3

Dans une fenêtre Windows Form, plusieurs événements peuvent déclencher une méthode asynchrone. Cette méthode télécharge un fichier et le met en cache. Mon problème est que je veux que cette méthode soit exécutée une fois. En d'autres termes, je veux empêcher le téléchargement du fichier plusieurs fois.Multithreading et concurence avec C#

Si la méthode de téléchargement du fichier est déclenchée deux fois, je souhaite que le second appel attende le fichier (ou attende que la première méthode soit terminée).

Est-ce que quelqu'un a une idée sur la façon d'y parvenir?

MISE À JOUR: J'essaie simplement d'empêcher les téléchargements inutiles. Dans mon cas, lorsqu'un client place sa souris sur un élément dans un ListBox pendant plus de quelques millisecondes, nous commençons à télécharger. Nous faisons l'hypothèse que l'utilisateur cliquera et demandera le fichier. Ce qui peut arriver, c'est que l'utilisateur garde sa souris sur l'élément pendant une seconde puis clique. Dans ce cas, deux téléchargements commencent. Je suis à la recherche de la meilleure façon de gérer un tel scénario.

MISE À JOUR 2:: Il est possible que l'utilisateur déplace sa souris sur plusieurs éléments. En conséquence, plusieurs téléchargements se produiront. Je n'ai pas vraiment de problème avec ce scénario, mais maintenant, si nous sommes confrontés à un tel scénario, nous n'abandonnons pas le téléchargement. Le fichier sera téléchargé (les fichiers sont généralement environ 50-100kb) et seront ensuite mis en cache.

+0

Si vous pouvez redresser certaines de mes hypothèses (ci-dessous), je peux mettre à jour ma réponse avec du code. –

+0

Plus de détails aideraient. Essayez-vous de vous assurer que la bande passante n'est pas divisée entre deux téléchargements concurrents ou évitez les téléchargements inutiles de la même ressource? – AnthonyWJones

+0

Pouvez-vous télécharger plusieurs fichiers à la fois? S'ils changent d'avis avant la fin du téléchargement, abandonnez-vous le premier téléchargement et en commencez un autre? –

Répondre

6

Maintenir l'état de ce qui se passe dans une variable de formulaire et votre méthode async vérifier cet état avant qu'il ne fait rien. Assurez-vous de synchroniser l'accès, cependant! Les mutex et sémaphores sont bons pour ce genre de chose.

Si vous pouvez télécharger différents fichiers simultanément, vous devez garder une trace de ce qui est téléchargé dans une liste à titre de référence.

Si un seul fichier peut être téléchargé à la fois et que vous ne voulez pas faire la mise en file d'attente, vous pouvez simplement décrocher l'événement pendant le téléchargement et le rebrancher lorsque le téléchargement est terminé.

+0

De manière générale, vous devez utiliser l'instruction lock {} chaque fois que cela est possible dans .Net. Les sémaphores et les mutex sont un peu trop robustes pour ce genre de situation. –

+0

Je serais d'accord si le problème était plus clairement défini. J'ai fait beaucoup de devinettes. –

+0

Une idée de pourquoi cela a été voté? Cela me semble être une réponse parfaitement raisonnable. –

0

Vous pouvez simplement envelopper votre appel de méthode dans une instruction de verrouillage comme celui-ci

private static readonly Object padLock = new Object(); 

... 
lock(padLock) 
{ 
    YourMethod(); 
} 
+0

La Question indique que la méthode est asynchrone, IOW renvoie rapidement une demande de téléchargement. Par conséquent, cette réponse n'aboutit à rien. – AnthonyWJones

+0

Cela peut être vrai, mais il déclare également qu'il veut que la deuxième requête attende la fin du premier ... annulant ainsi toutes les possibilités asynchrones. –

+0

En fait, un deuxième appel asynchrone qui se rend compte que le premier est toujours en cours de traitement resterait asynchrone à partir du POV de l'appelant. Cela nécessiterait que toutes les vérifications aient lieu dans la méthode asynchrone elle-même. –

0

Je ne sais pas comment il serait fait en C#, mais en Java, vous synchonize sur un objet static final privé dans la classe avant de télécharger le fichier. Cela bloquerait toute autre demande jusqu'à ce que l'actuelle soit complétée. Vous pouvez ensuite vérifier si le fichier a été téléchargé ou non et agir de manière appropriée.

private static final Object lock = new Object(); 
private File theFile; 

public method() { 
    synchronized(lock) { 
    if(theFile != null) { 
     //download the file 
    } 
    } 
} 
+0

synchonize { } en Java est à peu près équivalent à lock {} en C# –

+0

J'étais assez sûr qu'il y avait un équivalent, je ne savais pas ce que c'était. –

2

Voici une implémentation factice qui prend en charge les téléchargements de fichiers multiples:

Dictionary<string, object> downloadLocks = new Dictionary<string, object>(); 

    void DownloadFile(string localFile, string url) 
    { 
     object fileLock; 
     lock (downloadLocks) 
     { 
      if (!downloadLocks.TryGetValue(url, out fileLock)) 
      { 
       fileLock = new object(); 
       downloadLocks[url] = fileLock; 
      } 
     } 

     lock (fileLock) 
     { 
      // check if file is already downloaded 

      // if not then download file 
     } 
    } 
0

En général, je suis d'accord avec Michael, utilisez un lock autour du code qui est en fait le fichier. Toutefois, si un seul événement se produit toujours en premier et que vous pouvez toujours charger le fichier, pensez à utiliser Futures.Dans le cas initial, démarrez le fonctionnement futur

Future<String> file = InThe.Future<String>(delegate { return LoadFile(); }); 

et dans tous les autres cas, attendez sur la valeur de l'avenir

DoSomethingWith(file.Value); 
0

Si vous voulez un thread d'attendre un autre thread pour terminer une tâche, vous probablement vouloir utiliser un ManualResetEvent. Peut-être quelque chose comme ceci:

private ManualResetEvent downloadCompleted = new ManualResetEvent(); 
private bool downloadStarted = false; 

public void Download() 
{ 
    bool doTheDownload = false; 

    lock(downloadCompleted) 
    { 
     if (!downloadStarted) 
     { 
      downloadCompleted.Reset(); 
      downloadStarted = true; 
      doTheDownload = true; 
     } 
    } 

    if (doTheDownload) 
    { 
     // Code to do the download 

     lock(downloadCompleted) 
     { 
      downloadStarted = false; 
     } 
     // When finished notify anyone waiting. 
     downloadCompleted.Set(); 
    } 
    else 
    { 
     // Wait until it is done... 
     downloadCompleted.WaitOne(); 
    } 

} 
+0

note cela ne supporte qu'un téléchargement à la fois, si vous voulez 2 téléchargements simultanés de fichiers différents et seulement 2 threads, peut-être des discussions et des files d'attente avec synchronisation sont un meilleur choix –

+0

Je suis d'accord ... mais j'essayais juste d'illustrer l'utilisation de ResetEvents et ne pas mettre en œuvre l'ensemble du projet pour lui. :) – bobwienholt

Questions connexes