如果我正在更新DataRow,我是锁定整个DataTable还是只锁定DataRow?

7

假设我正在从多个线程访问一个DataTable。 如果我想要访问特定行,我怀疑我需要锁定该操作(我可能对此感到困惑,但至少我知道这样我是安全的):

// this is a strongly-typed table
OrdersRow row = null;
lock (orderTable.Rows.SyncRoot) {
    row = orderTable.FindByOrderId(myOrderId);
}

但是,如果我想要更新那一行,我应该再次锁定表格(或者更准确地说,是表格的Rows.SyncRoot对象),还是仅仅锁定那一行就可以了?

3个回答

5
实际上,在DataTable或DataRow中的一个地方执行lock并不会真正做任何事情。在使用Monitor锁(也就是lock块)时需要记住的一个重要方面是,锁定对象并不会对其进行任何操作;这就是一些人主张使用专用锁定对象而不是锁定资源本身的原因之一,因为它强制你意识到每当处理资源时必须执行锁定(并且在同一个对象上执行锁定)。
话虽如此,更好的做法是锁定整个DataTable,因为数据存储本身就在那里(DataRow对象内部仅包含一个偏移量,指示从哪里检索数据)。因此,即使您同步访问单个行,同时更新两个不同的行将导致您以非同步方式更新相同的数据存储机制。
在查看内部类型作为“黑盒子”和仅锁定所需内容之间存在冲突时,就会出现问题(在这种情况下,只锁定行会导致错误的结论),并尝试获得有关类型内部工作原理的见解并依赖可能会更改的实现细节。
总之,现在应该锁定整个DataTable以避免以非同步方式更新内部数据存储系统。

非常有见地的回答,我能理解你为什么觉得有必要指出lock机制的工作原理... 我确实意识到锁定不会对对象做任何事情;我想我本可以更好地表达我的问题,比如说“我需要按行或按表同步更新操作吗?”无论如何,现在对我来说很清楚,我必须同步整个表中任何行的更新——无论是通过锁定表还是专用的“表锁”(在这种情况下,我认为Rows.SyncRoot对象可以很好地发挥这个作用)。 - Dan Tao

3

在读取数据时不需要锁定,只有在写入/更新时才需要。尽可能地锁定最少的数据以确保数据一致性...通常只需锁定要更新的一行即可。如果您正在更新表之间的父子关系,则需要锁定每个表中的每一行。


Kevin提供的链接(http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/11b69e1a-ad6c-48d5-8e14-264af5b0692e)似乎表明锁定表是必要的。微软代表说:“假设更新单个行不会影响表中的其他任何内容是危险的,因为您依赖于可能在以后容易被破坏的潜在实现细节。”您是否有任何了解这是否正确的见解? - Dan Tao

3

1
这个链接说:“这种类型对于多线程读操作是安全的。您必须同步任何写操作。”这难道不意味着在多线程访问时需要使用锁吗? - code4life
我有点困惑;你提供的第一个链接似乎表明只需要锁定写入(尽管它没有说明要锁定什么)。第二个链接似乎表明锁定整个表是正确的方法。两者都似乎不同意你的说法,即你不能锁定表并期望读取是一致的。我有什么遗漏吗? - Dan Tao
我的第一条语句是错误的。我发现了矛盾的信息。你不需要锁定表来读取数据,因为这是可以的。你需要锁定表来写入数据。 - kemiller2002

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接