C# 如何确保一次只有一个线程可以访问DataTable
我有一个Windows控制台应用程序: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
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的问题保持不变。