2010-02-26 67 views
2

我正在編寫一個應用程序,顯示用戶可以選擇的對象列表,然後通過PropertyGrid控件查看和編輯屬性。通過使用輔助線程從文件中提取信息的耗時過程填充了對象的屬性。但是我還想讓用戶在提取過程正在進行時繼續查看其他對象。如何控制多個線程對一組對象的訪問?

在閱讀了關於SO的my previous問題的回答之後。這聽起來像是因爲提取過程寫入的屬性不能與用戶通過屬性網格編輯的屬性相交,所以我不應該在兩個線程同時編輯對象時遇到問題。儘管如果用戶看起來非常不幸並且屬性網格最終在非原子寫入過程中讀取對象,那麼用戶可能會看到不正確的值。

但是,我仍然想知道如何設置它來防止用戶編輯或查看正在提取中的對象。我對多線程非常陌生,但我已閱讀的大多數示例都顯示了一個單獨的令牌對象,該對象被創建爲用於鎖定對實際感興趣對象的訪問。我的另一個previous question的答案證實,通常創建一個像這樣的獨立對象專門用於鎖定。

所以,現在我想知道的是,在我的情況下,如何處理這些對象的大量集合?我想創建鎖,防止屬性網格顯示用戶選擇的對象,如果它正在被提取到。

我是否需要創建一個單獨的鎖對象集合,與我的真實集合保持同步?所以如果一個對象被添加或從我的主集合中刪除,我必須從我的鎖集合中添加或刪除鎖對象?

我是否鎖定實際對象而不是創建單獨的令牌鎖對象?

將「IsBeingExtracted」布爾屬性添加到屬性網格可以檢查以查看該對象是否正在寫入中間的對象呢?這將在提取過程的開始和結束時被設置。

或者如何引用當前正在提取的當前(如果有的話)對象的靜態字段。然後,屬性網格可以檢查請求顯示的最新對象是否不是由此靜態字段引用的對象?如果有多個提取線程,這當然不起作用。

什麼是最好的/正確的方法來做到這一點?就我個人而言,我最喜歡布爾屬性選項,但想知道其他人真正知道自己在做什麼的想法。

回答

1

難道你不能讓持有對象的集合爲SynchronizedCollection<T>?它將確保一次只有一個線程可以添加或訪問對象。然後,不要擔心如何同步訪問每個對象的屬性,請不要將該對象添加到該集合,直到它被填充。

事情是這樣的:

private readonly ICollection<Item> Items = new SynchronizedCollection<Item>(); 

// Run this on the background thread. 
public void PopulateItems() 
{ 
    using (var file = File.OpenRead("BigFile.txt")) 
    using (var reader = new StreamReader(file)) 
    { 
     while (!reader.EndOfStream) 
     { 
      var item = new Item(); 
      PopulateItem(item); 
      Items.Add(item); 
     } 
    } 
} 

public void PopulateItem(Item item) 
{ 
    // Do time-consuming work. 
} 

屬性網格可以快樂地做任何事情,因爲它在列表中顯示的時間與對象希望,提取線程完成它。不需要明確的鎖定。

0

使您的對象集合成爲字典,然後鎖定鍵。

-1

我認爲最好的方法是使用帶有超時的ManualResetEvent對象。這樣你可以告訴用戶它正在被提取,並在幾秒鐘內重試。

public class Item : IDisposable // I know it is a horrible class name... 
{ 
    private readonly ManualResetEvent accessibleEvent = new ManualResetEvent(false); 

    public void Extract() 
    { 
     try 
     { 
      // ..... 
     } 
     finally 
     { 
      accessibleEvent.Set(); // unlock    
     } 
    } 

    public void Edit() 
    { 
     if (!accessibleEvent.WaitOne(1000)) // wait 1 second 
     { 
      // notify user?  
     } 

     // .... 
    } 

    public void Dispose() 
    { 
     ((IDisposable)accessibleEvent).Dispose(); 
    } 
} 
+0

爲什麼鎖必須保持一秒鐘或更長時間?同步線程的一部分是儘量減少爭用時間。 – 2010-02-27 02:16:09

+0

@Rory - 這是等待編輯項目的時間量,而不是持有鎖的時間量。 – ChaosPandion 2010-02-27 02:19:54

0

通常,使用一個或多個鎖取決於您想要實現的併發程度。

你擁有的鎖越少(比如說一個全局鎖),那麼併發性就會降低,因爲許多操作可以競爭鎖並阻止對方運行。

您擁有的鎖越多,您可以實現的併發性就越高,但管理鎖的開銷越大。

使用作爲被修改對象的鎖是有意義的,如果你用鎖保護的只是這個對象。您會看到很多使用單獨對象的示例,因爲您不需要了解有關保護範圍的內容。

在你的具體情況下,我不太瞭解什麼是受保護的。你是否試圖阻止同時修改一個對象的屬性,即通過後臺進程或用戶?由於用戶一次不能做多件事,因此不需要大量的併發,因此不需要擁有多個鎖。 您可以做的是在屬性網格進入編輯模式並且後臺進程即將設置正在編輯的相同屬性(否則,不需要鎖定)時獲取單個鎖。