各位牛人救命啊,多线程操作DataTable 的问题

zhmvb 2009-03-15 05:25:42
一个静态的 DataTable,
程序启动后有多个线程来操作它,有的读其数据,有的修改其某行的数据,有的对其新增行,每个线程操作此 DataTable前 都加上了 lock(DataTable)。
加入了lock后有效的避免了并发操作的错误,但也出现了另一个问题:当某个线程在修改其数据时会报这个DataTable是"未将对象引用到实例”,可能是一个线程拿到这个对象后另一个线程又将其锁定了,结果这边这个对象就成了null了(不知道是不是这个原因)请教各位牛人如何解决次问题?
...全文
1395 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
reggielee 2011-09-03
  • 打赏
  • 举报
回复
while(flag)
{
flag = false;
DataTable的操作;
flag = true;
break;
}
要解决并发就只有让它等待。
游戏人间 2010-12-06
  • 打赏
  • 举报
回复
DataTable.Rows.SyncRoot这个应该同以的。
zhmvb 2009-03-17
  • 打赏
  • 举报
回复
lock 在数据量较大的情况下效率太差,换其他方式了
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
只有有操作和读取datatable的地方都锁了,当表中数据达到5000条已上时会报“未将对象引用设置到对象的实例”
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
只有有操作和读取datatable的地方都锁了,当表中数据达到5000条已上时会报“未将对象引用设置到对象的实例”
gisyellow 2009-03-16
  • 打赏
  • 举报
回复
lock的问题。。
  • 打赏
  • 举报
回复
for (int i = 0; i < selectrs.Length; i++)
{
selectrs[i].BeginEdit();
selectrs[i]["uiunique"] = selectrs[i]["uiunique"].ToString().Replace("(新)", "");
selectrs[i].EndEdit();
}


这个也要锁住,要知道你select返回的是一个数组,而这个数组里的每一个项其实就是你的table里的,如果你的table里把这个对象给删了或者在编辑,就会冲突聊


也就是说你的线程2的所有代码应该在lock里
jcobra 2009-03-16
  • 打赏
  • 举报
回复
打个标,学习一下
whitechololate 2009-03-16
  • 打赏
  • 举报
回复
学习中!~! 涨学问
mawering 2009-03-16
  • 打赏
  • 举报
回复
帮顶了,学习一下!
zzxap 2009-03-16
  • 打赏
  • 举报
回复
if (sender == this.buttonJRDL)//加入队列
selectrs = ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '待发' and infosendsoure2 = '紧急信息'");
if (sender == this.buttonLJFS) //立即发送
selectrs = ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '已发' and infosendsoure2 = '紧急信息'");
goonfighting 2009-03-16
  • 打赏
  • 举报
回复
各位牛人太帅了。
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 linaren 的回复:]
多线程读写肯定要进行同步处理了,最简单的办法设置个临界区,当线程处理的DataTable处于临界区内时,线程等待。
[/Quote]

有具体的例子吗?能否说的在详细点?谢谢了,我实在是没法子了,不知道这么设置临界区
linaren 2009-03-16
  • 打赏
  • 举报
回复
多线程读写肯定要进行同步处理了,最简单的办法设置个临界区,当线程处理的DataTable处于临界区内时,线程等待。
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
是不是lock不好用?总觉得lock的时候没有阻止其他线程操作datatable,有其他好用的锁吗?
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
线程2里的代码经过修改也同样出现了原来的错误:
修改后的代码:

if (sender == this.buttonJRDL)//加入队列
{
lock (ServiceBase.TBLInfoEntityMessageBase)
{
selectrs = (DataRow[])ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '待发' and infosendsoure2 = '紧急信息' and uiunique like '%(新)'").SyncRoot;
}
}
if (sender == this.buttonLJFS) //立即发送
{
lock (ServiceBase.TBLInfoEntityMessageBase)
{
selectrs = (DataRow[])ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '已发' and infosendsoure2 = '紧急信息' and uiunique like '%(新)'").SyncRoot;
}
}
for (int i = 0; i < selectrs.Length; i++)
{
selectrs[i].BeginEdit();
selectrs[i]["uiunique"] = selectrs[i]["uiunique"].ToString().Replace("(新)", "");
selectrs[i].EndEdit();
}

错误提示:此时表中有8000多条数据
zhmvb 2009-03-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 tmxk2002 的回复:]
if (sender == this.buttonJRDL)//加入队列
selectrs = ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '待发' and infosendsoure2 = '紧急信息'");
if (sender == this.buttonLJFS) //立即发送
selectrs = ServiceBase.TBLInfoEntityMessageBase.Select("infoarea = '已发' and infosendsoure2 = '紧急信息'");lock(ServiceBase.TBLInfoEntityMessageBase)
{
foreach (DataRow r in selectrs)
{
if (r["uiuni…
[/Quote]

将此处修改为下面代码后还是会出错误:


if (sendcommand == SendCommand.发送)
{
filterExpression = "infoid =" + messageentity.UIID + " and infotype = 'group' and infosendtype = '" + sendcommand.ToString() + "' and infoarea = '已发' and infosendtime >='" + DateTime.Now.ToString("yyyy-MM-dd 00:00:00.0000") + "' and infosendtime <='" + DateTime.Now.ToString("yyyy-MM-dd 23:59:59.9999") + "'";
lock (ServiceBase.TBLInfoEntityMessageBase)
{
pidcount = (new DataView(ServiceBase.TBLInfoEntityMessageBase, filterExpression, string.Empty, DataViewRowState.CurrentRows))[0]["infopointidcount"].ToString();
}
}
else
{
filterExpression = "infoid =" + messageentity.UIID + " and infotype = 'point' and infosendtype = '" + sendcommand.ToString() + "' and infoarea = '已发' and infosendtime >='" + DateTime.Now.ToString("yyyy-MM-dd 00:00:00.0000") + "' and infosendtime <='" + DateTime.Now.ToString("yyyy-MM-dd 23:59:59.9999") + "'";
lock (ServiceBase.TBLInfoEntityMessageBase)
{
pidcount = (new DataView(ServiceBase.TBLInfoEntityMessageBase, filterExpression, string.Empty, DataViewRowState.CurrentRows)).Count.ToString();
}
}



出错的提示分别是:
索引超出了数组界限。此时表中有8000多条数据

tangyishi 2009-03-16
  • 打赏
  • 举报
回复
同意楼上的,select的锁不正确。
另外this.dataGridView1.DataSource = db;你这个数据源绑定到UI了,可能也会导致问题吧。。。
  • 打赏
  • 举报
回复
private void select(object v)
{
while (true)
{
Monitor.Enter(db);
var rs = db.Select("id > 10000");
Monitor.Exit(db);
for (int i = 0; i < rs.Length; i++)
{
rs[i]["id"] = (new Random()).Next();
rs[i]["tm"] = DateTime.Now.ToShortTimeString();
}

}
}


像上楼的人的说的,你把红色的地方放到锁里,你看会不会报?

public object this[string columnName]
{
get
{
DataColumn dataColumn = this.GetDataColumn(columnName);
int defaultRecord = this.GetDefaultRecord();
return dataColumn[defaultRecord];
}
set
{
DataColumn dataColumn = this.GetDataColumn(columnName);
this[dataColumn] = value;
}
}
这是你对row的列赋值的代码,不知有一个简单的赋值语句的
  • 打赏
  • 举报
回复
多线程的锁,锁的应该是会互相操作某对象的代码逻辑,而不是对象本身。锁住同一个对象只是会产生相同的锁,达到同步的作用。你获取了某个对象,如果你调用了这个对象的方法,就要考虑同步这个方法,因为这个方法里可能就调用了你共享对象。
加载更多回复(17)

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧