Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确保一次只有一个线程可以访问DataTable_C#_.net_Console Application - Fatal编程技术网

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

C# 如何确保一次只有一个线程可以访问DataTable,c#,.net,console-application,C#,.net,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.Ro

我有一个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();
        }
    }
}
使用系统;
使用系统文本;
命名空间线程锁示例
{
班级计划
{
静态空隙P1(System.Data.DataTable dt)
{
对于(int i=0;i<100000;i++)
{
dt.行。添加(i);
}
}
静态无效P2(System.Data.DataTable dt)
{
对于(int i=100000;i<200000;i++)
{
dt.行。添加(i);
}
}
静态void Main(字符串[]参数)
{
System.Data.DataTable dt=新的System.Data.DataTable();
对于(int i=0;i<200;i++)
dt.列。添加(“Id”+i);
System.Threading.Thread t1=新的System.Threading.Thread(()=>P1(dt));
System.Threading.Thread t2=新的System.Threading.Thread(()=>P2(dt));
t1.Start();
t2.Start();
t1.Join();
t2.连接();
}
}
}

现在,我正在传递一个可供两个线程访问的数据表,但应用程序已冻结-如何更改代码以消除此问题。

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

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

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

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

  • 加锁
创建如下所示的锁定对象:

private static object _lock = new object();
现在,您可以通过以下方式围绕对数据表的调用:

lock (_lock)
{
    dt.Rows.Add(i);
}
  • 不要直接使用线程。而是使用任务并行库:
Task
对象是线程周围的智能包装器。建议使用任务

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

Task.WaitAll(t1, t2);
更新

既然原来的问题现在从僵局变为僵局,还有两件事需要考虑。 在控制台应用程序中,您必须始终在某个时间点等待,直到两个任务完成。这种等待将冻结您的UI。当然,你可以使用一些聪明的东西,比如定时器来检查任务是否完成了,或者其他什么,但是控制台应用程序实际上并不适合这种情况

但是,如果您的应用程序实际上是WinForms或WPF应用程序,那么您应该考虑使用异步代码,并在C#5中添加新的async/await关键字。它们可以完美地处理任务,让您在另一个线程上运行代码,同时UI保持响应。当任务完成时,结果会合并回您的UI线程,用户会保留一个响应应用程序


有关async/await的更多信息,您可以从这里开始:

除了Wouter de Kort的答案之外:

如果要在DataTable上使用锁,请使用DataTable.Rows.SyncRoot对象,如

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

因为它是假定的锁对象。

没有单个
lock
语句的死锁?我不认为这是你的应用程序冻结的原因。取决于场景,但在这里,我将使用ConcurrentQueue收集数据,然后在某个线程安全的位置填充DataTable。首先,您可以使用lock语句或互斥体,或者获取该DataTable的reid。@TomTomTom-操作应该发生在DataTable上-我无法摆脱它。在任何情况下,OP如何确保只有1个线程可以访问数据表一次创建一个数据表。死锁或无死锁OP的问题保持不变。