Многопоточность и параллелизм с C # - PullRequest
3 голосов
/ 15 января 2009

В окне Windows Form несколько событий могут вызывать асинхронный метод. Этот метод загружает файл и кэширует его. Моя проблема в том, что я хочу, чтобы этот метод был выполнен один раз. Другими словами, я хочу предотвратить загрузку файла несколько раз.

Если метод загрузки файла запускается дважды, я хочу, чтобы второй вызов дождался файла (или дождался выполнения первого метода).

У кого-нибудь есть идеи, как этого добиться?

ОБНОВЛЕНИЕ : Я просто пытаюсь предотвратить ненужные загрузки. В моем случае, когда клиент наводит указатель мыши на элемент в ListBox более чем на пару миллисекунд, мы начинаем загрузку. Мы предполагаем, что пользователь щелкнет и запросит файл. Что может произойти, так это то, что пользователь удерживает курсор мыши над элементом в течение одной секунды, а затем щелкает. В этом случае начинаются две загрузки. Я ищу лучший способ справиться с таким сценарием.

ОБНОВЛЕНИЕ 2: : Существует вероятность того, что пользователь наведет указатель мыши на несколько элементов. В результате произойдет многократная загрузка. Мне не очень сложно с этим сценарием, но сейчас, если мы столкнемся с таким сценарием, мы не откажемся от загрузки. Файл будет загружен (файлы обычно имеют размер около 50-100 КБ) и затем будет кэширован.

Ответы [ 6 ]

6 голосов
/ 15 января 2009

Поддерживайте состояние того, что происходит в переменной формы, и попросите ваш асинхронный метод проверить это состояние, прежде чем оно что-либо сделает. Убедитесь, что вы синхронизируете доступ к нему! Мьютексы и семафоры хороши для такого рода вещей.

Если вы можете загружать разные файлы одновременно, вам нужно будет отслеживать, что загружается в списке для справки.

Если за один раз можно загрузить только один файл, и вы не хотите ставить вещи в очередь, вы можете просто отцепить событие, пока что-то загружается, и повторно подключить его после завершения загрузки. *

2 голосов
/ 15 января 2009

Вот фиктивная реализация, которая поддерживает загрузку нескольких файлов:

    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 голосов
/ 15 января 2009

Если вы хотите, чтобы один поток ожидал завершения другого потока, возможно, вы захотите использовать ManualResetEvent. Может быть, что-то вроде этого:

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 голосов
/ 15 января 2009

В общем, я согласен с Михаилом , используйте lock вокруг кода, который фактически получает файл. Однако, если сначала происходит единственное событие, и вы всегда можете загрузить файл, попробуйте использовать Futures . В начальном событии запустите будущий ход

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

и в любом другом событии, ждите будущего значения

DoSomethingWith(file.Value);
0 голосов
/ 15 января 2009

Я не уверен, как это будет сделано в C #, но в Java вы должны синхронизировать частный статический конечный объект в классе перед загрузкой файла. Это будет блокировать любые дальнейшие запросы, пока текущий не будет завершен. Затем вы можете проверить, был ли файл загружен или нет, и действовать соответствующим образом.

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

public method() {
  synchronized(lock) {
    if(theFile != null) {
      //download the file
    }
  }
}
0 голосов
/ 15 января 2009

Вы можете просто обернуть ваш вызов метода в оператор блокировки, как это

private static readonly Object padLock = new Object();

...
lock(padLock)
{
    YourMethod();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...