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

Exp*_*ice 0 .net c# console-application

我有这个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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我传递的DataTable可以访问两个线程,但应用程序冻结 - 如何更改我的代码以删除此问题.

Wou*_*ort 6

运行此应用程序时,您不会遇到死锁.相反,您会收到一条错误,指出某些数据已损坏,DataTable因为它DataTable本身有一些内部的并发检查.

我想这个应用程序是你的真实应用程序的简单版本.您可以采取以下几个步骤来改进您的计划:

  • 避免使用共享数据进行多线程处理

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

如果不可能,您可以执行以下操作:

  • 添加锁

你创建一个像这样的锁对象:

private static object _lock = new object();
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用以下命令对数据表进行调用:

lock (_lock)
{
    dt.Rows.Add(i);
}
Run Code Online (Sandbox Code Playgroud)
  • 不要直接使用Threads.而是使用任务并行库:

一个Task目标是围绕一个主题的智能包装.建议使用任务.

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

Task.WaitAll(t1, t2);
Run Code Online (Sandbox Code Playgroud)

UPDATE

由于最初的问题现在已从死锁变为冻结,因此还需要考虑其他一些事项.

在控制台应用程序中,您将始终等待某个时间点,直到完成两个任务.等待将冻结您的UI.当然,你可以使用像Timer这样的聪明的东西来检查任务是否已完成,但是控制台应用程序确实不适用于这种情况.

但是,如果您的应用程序实际上是一个WinForms或WPF应用程序,您应该考虑使用异步代码和C#5中添加的新async/await关键字.它们与Tasks完美配合,它们允许您在另一个线程上运行代码,同时UI保持响应.任务完成后,结果将合并回UI线程,用户将保留响应式应用程序.

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