2009-01-14 94 views
3

在Windows窗體窗口中,多個事件可以觸發異步方法。該方法下載一個文件並對其進行緩存。我的問題是我想讓該方法執行一次。換句話說,我想阻止文件被多次下載。C多線程和協議#

如果下載文件的方法被觸發兩次,我希望第二個調用等待文件(或等待第一個方法完成)。

有人有關於如何實現這一點的想法?

UPDATE:我只是試圖防止不必要的下載。在我的情況下,當客戶將鼠標放在ListBox中的某個項目上超過幾毫秒時,我們開始下載。我們假設用戶將點擊並請求文件。可能發生的事情是,用戶將鼠標懸停在項目上一秒鐘,然後單擊。在這種情況下,兩個下載開始。我正在尋找處理這種情況的最佳方式。

UPDATE 2::用戶可能會將鼠標移動到多個項目上。結果是,會發生多次下載。在這種情況下,我並沒有很強硬,但現在如果我們面對這種情況,我們不會放棄下載。該文件將被下載(文件通常在50-100kb左右),然後將被緩存。

+0

如果你能理清我的一些假設(下面),我可以用代碼更新我的答案。 – 2009-01-14 21:33:14

+0

更多細節將有所幫助。您是否試圖確保兩個相互競爭的下載之間的帶寬沒有被分割或避免不必要地下載相同的資源? – AnthonyWJones 2009-01-14 21:33:31

+0

你可以一次下載多個文件嗎?如果他們在下載完成之前改變主意,是否放棄第一次下載並開始另一次下載? – 2009-01-14 22:39:14

回答

6

維護表單變量發生的狀態,並讓異步方法在執行任何操作之前檢查該狀態。不過,請確保您同步訪問權限!互斥和信號量對於這種事情是很好的。

如果你可以同時下載不同的文件,你需要跟蹤列表中下載的內容以供參考。

如果一次只能下載一個文件,並且您不想排隊,那麼您可以在正在下載某些內容時解除該事件,並在下載完成時重新掛鉤。

0

你可以簡單地鎖語句中包裝你的方法調用這樣

private static readonly Object padLock = new Object(); 

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

Question說明方法是異步的,IOW它具有快速返回調度下載請求。因此,這個答案沒有任何結果。 – AnthonyWJones 2009-01-14 21:29:04

0

我不知道它將如何在C#中完成,但在Java中,你會synchonize的私有靜態最後對象在下載文件之前在類中。這將阻止任何進一步的請求,直到當前的請求完成。然後,您可以檢查文件是否被下載,並採取適當的行動。

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

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

這裏是一個虛擬實現,它支持多種文件下載:

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

一般情況下,我同意Michael,使用lock各地實際獲取該文件的代碼。但是,如果始終首先發生一個事件,並且始終可以加載該文件,那麼請考慮使用Futures。在最初的情況下,開始未來運行

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

,並在所有其他情況下,等待未來的價值

DoSomethingWith(file.Value); 
0

如果你想一個線程等待另一個線程完成一個任務,你可能要使用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(); 
    } 

}