C#多线程处理DataRow时报错
答案:4 悬赏:80 手机版
解决时间 2021-02-01 13:38
- 提问者网友:骨子里的高雅
- 2021-02-01 09:31
C#多线程处理DataRow时报错
最佳答案
- 五星知识达人网友:山河有幸埋战骨
- 2021-02-01 11:02
问题出在后台线程,但问题的根源却在启动10线程的foreach循环上!
改成这样就不会出问题了。
for (int i = 0; i < 10; i++ )
{
DataRow row = db.Rows[0];
Thread t = new Thread(new ParameterizedThreadStart(run));
t.IsBackground = true;
t.Start(row);
Thread.Sleep(1);
}问题分析:
虽然DataTable db是一个局部变量(注意这个变量是一个DataRow的集合) ,但在每个线程都引用了这个集合中的元素 —— 数据行。在多线程环境下,IEnumerable不是线程安全的,往往导致遍历的序数异常(就是你看到那个异常),而 foreach 使用了IEnumerable!
追问多谢你的答复,改完后报“DataTable 内部索引已损坏:“5”。”的错,如图所示
追答public partial class Form1 : Form
{
DataTable db = new DataTable();
//……
private void Form1_Load(object sender, EventArgs e)
{
//……
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(run));
t.IsBackground = true;
t.Start(db.Rows[i]);
Thread.Sleep(1);
}
}
private void run(object row)
{
DataRow r = (DataRow)row;
while (true) //循环结构变一下
{
//必须锁住DataTable.Rows.SyncRoot!
lock (db.Rows.SyncRoot)
{
r[1] = DateTime.Now.ToString();
Thread.Sleep(10);
}
}
}
}追问锁住后只有第一个线程在正常工作,第一个线程没有退出来前其他的线程都在等待。追答多线程试图锁住一个DataRow进行操作,会导致DataTable中的Columns集合遍历序数异常。在你的程序中,不同线程操作操作不同的行,咋一看,似乎不lock也可以,但真的这么做了却证明是行不通的,因为在DataTable中,除了有Rows集合,还有Columns集合。每个线程确实在操作Rows集合中的一个项(行),Rows集合中所有的行都共用一个Columns集合,你锁住了行,却没有锁住Columns集合!
另一方面,.net 之所以在DataTable.Rows集合上提供.SyncRoot同步对象,正是为了在多线程环境下锁住DataTable中的Rows集合同时也锁住了Columns集合。
改成这样就不会出问题了。
for (int i = 0; i < 10; i++ )
{
DataRow row = db.Rows[0];
Thread t = new Thread(new ParameterizedThreadStart(run));
t.IsBackground = true;
t.Start(row);
Thread.Sleep(1);
}问题分析:
虽然DataTable db是一个局部变量(注意这个变量是一个DataRow的集合) ,但在每个线程都引用了这个集合中的元素 —— 数据行。在多线程环境下,IEnumerable不是线程安全的,往往导致遍历的序数异常(就是你看到那个异常),而 foreach 使用了IEnumerable!
追问多谢你的答复,改完后报“DataTable 内部索引已损坏:“5”。”的错,如图所示
追答public partial class Form1 : Form
{
DataTable db = new DataTable();
//……
private void Form1_Load(object sender, EventArgs e)
{
//……
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(run));
t.IsBackground = true;
t.Start(db.Rows[i]);
Thread.Sleep(1);
}
}
private void run(object row)
{
DataRow r = (DataRow)row;
while (true) //循环结构变一下
{
//必须锁住DataTable.Rows.SyncRoot!
lock (db.Rows.SyncRoot)
{
r[1] = DateTime.Now.ToString();
Thread.Sleep(10);
}
}
}
}追问锁住后只有第一个线程在正常工作,第一个线程没有退出来前其他的线程都在等待。追答多线程试图锁住一个DataRow进行操作,会导致DataTable中的Columns集合遍历序数异常。在你的程序中,不同线程操作操作不同的行,咋一看,似乎不lock也可以,但真的这么做了却证明是行不通的,因为在DataTable中,除了有Rows集合,还有Columns集合。每个线程确实在操作Rows集合中的一个项(行),Rows集合中所有的行都共用一个Columns集合,你锁住了行,却没有锁住Columns集合!
另一方面,.net 之所以在DataTable.Rows集合上提供.SyncRoot同步对象,正是为了在多线程环境下锁住DataTable中的Rows集合同时也锁住了Columns集合。
全部回答
- 1楼网友:痴妹与他
- 2021-02-01 13:49
while (true) 在搞鬼,你的这个死循环有什么用呢?
- 2楼网友:西岸风
- 2021-02-01 12:20
lock (row)//锁定此行
你都锁定了,还改?追问lock(row)的含义是不让其它线程来来更改这一行的内容,关起门来自己改。代码在断点测试的时候是没问题的,但是取消断点后就报错,这是个多线程的问题造成的。
你都锁定了,还改?追问lock(row)的含义是不让其它线程来来更改这一行的内容,关起门来自己改。代码在断点测试的时候是没问题的,但是取消断点后就报错,这是个多线程的问题造成的。
- 3楼网友:一秋
- 2021-02-01 11:09
把你线程的传入参数,由原本的t.Start(row); 改为t.Start(row.ItemArray)
同样下面的DataRow r = (DataRow)row;同样修改为object[] arr=(object[])row;看看
你那个lock用法不对,可以去掉。追问1、t.Start(row); 改为t.Start(row.ItemArray)后,再做的修改就无法体现到Form1_Load中所建的db当中了,这是我简化后的代码;
2、要求是多线程传的参数中row的修改可以体现到db当中,然后再用其他的线程做统一处理。
同样下面的DataRow r = (DataRow)row;同样修改为object[] arr=(object[])row;看看
你那个lock用法不对,可以去掉。追问1、t.Start(row); 改为t.Start(row.ItemArray)后,再做的修改就无法体现到Form1_Load中所建的db当中了,这是我简化后的代码;
2、要求是多线程传的参数中row的修改可以体现到db当中,然后再用其他的线程做统一处理。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯