如何确保一次只有1个线程可以访问DataTable

本文关键字:线程 1个 DataTable 访问 一次 何确保 确保 | 更新日期: 2023-09-27 18:02:46

我有这个Windows控制台应用程序:

using System;
using System.Text;
namespace ThreadLockSample
{
    class Program
    {
        static void P1(System.Data.DataTable dt)
        {
            for (int i = 0; i < 100000; i++)
            {
                dt.Rows.Add(i);
            }
        }
        static void P2(System.Data.DataTable dt)
        {
            for (int i = 100000; i < 200000; i++)
            {
                dt.Rows.Add(i);
            }
        }
        static void Main(string[] args)
        {
            System.Data.DataTable dt = new System.Data.DataTable();
            for (int i = 0; i < 200; i++)
                dt.Columns.Add("Id " + i);
            System.Threading.Thread t1 = new System.Threading.Thread(() => P1(dt));
            System.Threading.Thread t2 = new System.Threading.Thread(() => P2(dt));
            t1.Start();
            t2.Start();
            t1.Join();
            t2.Join();
        }
    }
}

现在我正在传递一个数据表访问两个线程,但应用程序冻结-我怎么能改变我的代码,以消除这个问题。

如何确保一次只有1个线程可以访问DataTable

运行此应用程序时,不会出现死锁。相反,您会得到一个错误,说明DataTable中的一些数据损坏了,因为DataTable本身有一些内部并发检查。

我想这个应用程序是一个简单的版本,你可以采取几个步骤来改进你的程序:

  • 避免使用共享数据的多线程
使用共享数据的多线程是困难的。你能简化你的程序,使你不需要任何共享数据吗?也许你可以并行运行两个操作,返回一个结果,然后合并这些结果。这将使您避免许多潜在的问题。

如果这是不可能的,你可以这样做:

    <
  • 加锁/gh>

创建一个锁对象,如下所示:

private static object _lock = new object();

现在你用:

包围对datatable的调用
lock (_lock)
{
    dt.Rows.Add(i);
}
    不要直接使用线程。而是使用任务并行库:

Task对象是围绕线程的智能包装器。建议使用Tasks

Task t1 = Task.Run(() => P1(dt));
Task t2 = Task.Run(() => P2(dt));
Task.WaitAll(t1, t2);

更新

由于原来的问题现在从死锁改为冻结,因此您需要考虑其他一些事情。

在控制台应用程序中,您总是需要等待两个任务完成。这种等待会冻结你的UI。当然,你可以使用定时器来检查任务是否完成,但控制台应用程序真的不适合这种情况。

然而,如果你的应用实际上是一个WinForms或WPF应用,你应该考虑使用c# 5中添加的async/await关键字的异步代码。它们与任务完美配合,让你在另一个线程上运行代码,同时UI保持响应。当Task完成时,结果被合并回你的UI线程,用户保持一个响应的应用程序。

有关async/await的更多信息,可以从这里开始:使用async和await进行异步编程(c#和Visual Basic)

除了Wouter de Kort的回答:

如果您想在数据表上使用锁,请使用DataTable. rows . syncroot对象,如

lock(dt.Rows.SyncRoot)
    //Your code here

因为它是假定的锁对象