2011-05-15 259 views
3

我有一個叫做DataStorage的單例obj,它在我的應用程序中存儲公共數據;其中一個是名爲myTable的Datatable,它將被多個線程讀取和寫入。我有一個私人物件,用來作爲數據存儲鎖即C#:datatable線程安全問題

private object lockObj = new object(); 

我已經纏訪問myTable的這樣鎖:

private DataTable myTable; 
public DataTable MyTable 
{ 
    get 
    { lock(lockObj) { return myTable; } } 
    set 
    { lock(lockObj) { myTable = value; } } 
} 

另一個目的,即MyObj中會得到這樣的數據表,做一個選擇然後在Select中修改檢索到的DataRow []中的某個值。我已閱讀,選擇是不是線程安全的,所以我寫了我這樣的代碼:

// lock on MyTable 
DataTable dt = DataStorage.Instance.MyTable; 

lock (MyObjLockObj) // lock object for MyObj class 
{ 
    // do a select, then modify value in the returned row 
    DataRow[] foundRows = dt.Select("some expression"); 
    foundRows[0]["some col"] = 123456; 
} 

問題: 1.總體而言,這是代碼線程安全的?

  1. 當我在MyObj中修改檢索的DataRow時,MyTable設置程序是否確保其線程安全?因爲setter用於設置DataTable,而不是DataRow。

  2. 我是否應該將訪問DataStorage.Instance.MyTable的代碼移動到與Select?相同的鎖定塊中?

在此先感謝。

回答

1

你代碼的心不是線程安全的,這是因爲:

的財產鎖只能確保一個以上的線程不能使用在同一時間的get/set屬性,但它們可以訪問後,他們可以改變它同一時間。

一個線程可以使用MyTable財產DataTable的instacne得到。 之後,另一個可以使用該屬性來獲取相同的實例。 然後他們都可以訪問myTable後,他們都可以直接寫入而不需要同步。

因此,將存取器移入鎖不會有幫助。

它更好地提供更改數據的方法,並在這些方法中執行同步,而不直接公開數據表。

+0

感謝您的洞察力,我已將將數據表中的值更改回單身對象的責任。 – cks2k2 2011-05-16 10:42:00

1

getter和setter中的那些鎖完全沒用。 'myTable = value'操作已經是原子操作,不需要將其封裝在一個鎖中。當然,這個鎖與修改行無關。然而,該鎖(MyObjLockObj)確保只有一個線程將訪問您的數據表,如果通過您的應用程序使用相同的MyObjLockObj。如果你不經常使用這個數據表,那麼這不會成爲問題,但是如果你的應用程序全都與這個數據表相關,那麼你會遇到性能問題。總而言之,在多線程應用程序中使用單個數據表是一個不好的決定。如果您從數據庫中讀取該數據表的數據,則應該爲每個線程讀取一個數據表,修改其行,並將更改提交回數據庫。

+0

啊,我明白你的意思了。獲得者只確保1個線程獲取表,但在退出鎖之後,任何人都可以重新獲取並修改它。 – cks2k2 2011-05-16 10:43:14