DataTable和线程安全

时间:2011-07-19 08:55:47

标签: .net asp.net multithreading ado.net thread-safety

我将DataTable存储在ASP .NET Cache属性中。可以在该DataTable上执行的操作是:

  • 绑定到网格控件(第三方网格内部管理数据源对象,回发后其DataSource为NULL,我假设一旦数据被绑定,它就不再使用数据源DataTable了)
  • 从DataTable中删除行( Row.Delete()

我在显式处理该DataTable实例时添加了基本的读取器/编写器锁,但我不知道该解决方案是否存在任何其他线程安全问题。我猜想当网格控件在DataBinding中间时,某些东西可能会出错,而其他线程会删除行?如果是这样,我如何同步对该表的访问权限,以便在绑定网格控件时不进行删除方法调用?是否有任何事件组合,我可以把AcquireWriterLock& ReleaseWriterLock方法?

谢谢,帕维尔

3 个答案:

答案 0 :(得分:2)

如果您通过数据绑定公开数据表,那就算了;你不能做那个线程安全的。即使你以某种方式(在自定义DataView中)包装ITypedList,这还不够 - 数据绑定会对数据做出假设,特别是IList等 - 例如,它不会在迭代数据或在UI线程上添加行的中间以线程争用的方式随机更改长度。

通过事件在同一个线程上进行的更改<...>但不是交叉线程。

答案 1 :(得分:0)

正如人们在其他答案中提到的那样:

  • 通常你只缓存不可变数据(或者至少:在它存在时将其视为不可变的)。否则它不是缓存
  • 如果有人要编辑,请不要向公共数据公开多个请求
  • 如果您通过数据绑定公开数据表,那就忘了它;你不能做那个线程安全的

但是我真的需要缓存一个DataTable。原因:

  • 获得结果的查询真的很大&amp;耗时的。此外,使用该查询进行调用的页面刷新率也很高。结果,数据库引擎变得越来越忙。通过缓存,我每2分钟只能获得1分贝的引擎调用
  • 该查询的结果不同。但是,用户可以完全接受相同的结果,比方说,2分钟。因此,将数据存储在缓存中2分钟是可以接受的。此外,没有其他问题,如并发,乐观/悲观离线锁......

但是,当用户对其看到的数据进行操作时,会对数据进行一些更改:

  • 必须在db上应用更改。在实现缓存之前,应用更改为db之后,应用程序再次发出巨大的查询以获得仅有轻微差异的结果
  • 现在,通过缓存,更改将应用​​于db并应用于缓存的DataTable。然后该数据表再次绑定到数据绑定控制。好处:无需进行WCF调用,使用大量查询获取数据+将数据传输到Web应用程序

这就是我为该解决方案实现锁定的方式:

  1. 缓存数据存储在类似单身的包装器中:

    public class AllocationQueue
    {
        private static object tableSyncRoot = new object();
    
  2. 这是修改缓存的DataTable的唯一代码:

    internal void RemoveTaskRowFromAllocationQueue(Guid queueId, Guid taskId)
    {
        var allocationQueueEntry = GetAllocationQueueEntry(queueId);
        var queueData = allocationQueueEntry.TaskIdIndexedView;
        lock(tableSyncRoot)
        {
            int rowIndex = queueData.Find(new object[] { taskId });
            queueData[rowIndex].Delete();
        }
    }
    
  3. 这是暴露数据绑定数据的唯一代码:

    public DataTable GetAllocationQueue(Guid queueId, string filter)
    {
        var allocationQueueEntry = GetAllocationQueueEntry(queueId);
        lock (tableSyncRoot)
        {
            var rows = allocationQueueEntry.Table.Select(filter);
            if (rows.Length > 0)
            {
                return rows.CopyToDataTable<DataRow>();
            }
        }
        return null;
    }
    
  4. 线程安全&amp;就像一个魅力(我是对的吗:)。但这对我的要求非常具体。

答案 2 :(得分:0)

这是一种以线程安全的方式添加行的简单方法。其中 dt = 我的 DataTable 和 dr = 我的 DataRow

lock (dt.Rows.SyncRoot)
{
    dt.Rows.Add(dr);
}