【发布时间】:2016-11-05 11:23:30
【问题描述】:
我以为我知道lock 语句的工作原理,但似乎我不知道......我正在尝试实现使我能够从单独的线程(WinForms 项目)同时向/从DataSet 添加和删除行的功能)。因此,一个线程每隔一段时间向DataSet 添加新行,而另一个线程从同一DataSet 删除行。我假设DataSet 总是有一些行要删除——我想在这里关注多线程问题。向DataSet 添加行的线程比删除行的线程运行得更快。为了创建新线程,我使用System.Threading.Timer 类,它在此类上创建新实例时启动新线程。我不明白为什么在我的代码中有lock 语句时仍然得到System.InvalidOperationException。进一步的消息是:“附加信息:检测到跨线程操作。”
我应该如何使用lock 语句?
我应该将lock 语句放在我的代码中的什么位置?
代码:
using System;
using System.Data;
using System.Threading;
using System.Windows.Forms;
namespace TEST_WinForms
{
public partial class Form1 : Form
{
private const String _strDSname = "dataSet";
private const String _strTableName = "dtBuffer";
private object _objLockDataSet = new object();
public Form1()
{
InitializeComponent();
}
private void BuildDataSet()
{
DS = new DataSet();
DS.Tables.Add(_strTableName);
foreach (DataTable table in DS.Tables)
{
table.Columns.Add("LP", typeof(Int32));
table.Columns.Add("Date and time", typeof(DateTime));
}
}
private void StartT1timer()
{
try
{
if (T1 == null)
{
T1 = new System.Threading.Timer(new TimerCallback(AddRow)
, null
, 0
, Timeout.Infinite);
}
else
{
T1.Change(0, Timeout.Infinite);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void StartT2timer()
{
try
{
if (T2 == null)
{
T2 = new System.Threading.Timer(new TimerCallback(DeleteRow)
, null
, 1000
, Timeout.Infinite);
}
else
{
T2.Change(1000, Timeout.Infinite);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void AddRow(object state)
{
lock (_objLockDataSet)
{
try
{
this.Invoke(new MethodInvoker(() =>
{
DataRow newRow = DS.Tables[_strTableName].NewRow();
if (DS.Tables[_strTableName].Rows.Count > 0)
{
newRow["LP"] =
(int)DS.Tables[_strTableName].Rows[DS.Tables[_strTableName].Rows.Count - 1]["LP"] + 1;
}
else
{
newRow["LP"] = 1;
}
newRow["Date and time"] = DateTime.Now;
DS.Tables[_strTableName].Rows.Add(newRow);
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
T1.Change(100, Timeout.Infinite);
}
private void DeleteRow(object state)
{
try
{
lock (_objLockDataSet)
{
if (DS.Tables[_strTableName].Rows.Count > 0)
{
DS.Tables[_strTableName].Rows.RemoveAt(0);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
T2.Change(500, Timeout.Infinite);
}
private void Form1_Load(object sender, EventArgs e)
{
BuildDataSet();
gridControl1.DataSource = DS.Tables[_strTableName];
StartT1timer();
StartT2timer();
}
private DataSet DS
{
get;
set;
}
private System.Threading.Timer T1
{
get;
set;
}
private System.Threading.Timer T2
{
get;
set;
}
}
}
【问题讨论】:
-
为什么应该是
DataTable?使用 .NET 中提供的concurrent collections 之一 -
一个数据集可以包含一个DataTables @dotctor的集合,这里的问题实际上是当添加行时它在删除行或列时起作用,操作必须使用负计数器执行for循环,从从最高到最低..
标签: c# multithreading concurrency dataset locking