2011-05-15 258 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