我想对DataTable / DataSet进行线程安全的更新操作。有大约20个线程,每个线程使用DataTable的Rows.Find(pk)
方法更新~40行全局DataTable。每个线程都将更新DataTable的不同行。
我正在为DataSet使用以下包装类。这种方法是否是线程安全的?
public sealed class MyDataSet{
public static DataSet ds = new DataSet();
public static UpdateRow(key,data)
{
object _lock = new object();
DataRow dr = ds.Tables[0].Rows.Find(key);
lock(_lock){
dr.AcceptChanges();
dr.BeginEdit();
dr["col"] = data;
dr.EndEdit();
}
}
}
从for
循环调用此方法。
for(int x=0; x<40; x++;){
if(someCondition)
.
.
.
MyDataSet.UpdateRow(key,data);
.
.
.
}
一切都在多线程环境中完成。 UpdateRow方法线程安全吗?
答案 0 :(得分:5)
不,这不安全。您应该在以下位置更改您的代码:
public sealed class MyDataSet{
public static DataSet ds = new DataSet();
private static object _lock = new object();
public static UpdateRow(key,data)
{
lock(_lock){
DataRow dr = ds.Tables[0].Rows.Find(key);
dr.AcceptChanges();
dr.BeginEdit();
dr["col"] = data;
dr.EndEdit();
}
}
}
您的_lock
对象应该是程序中的静态对象,以使其成为一个很好的锁。而你的Find
应该在锁定的部分。
答案 1 :(得分:1)
UpdateRow方法线程安全吗?
不,不是。每次输入方法时,您都会在新对象上创建锁定。您锁定的对象必须在所有线程中保持相同 - 否则锁将永远不会被视为“被采用”,因为每个线程都会愉快地在它之后抛弃的对象上创建一个新锁。实现这一目标的一种方法是使你锁定的对象也是静态的。