Reputation: 543
I thought I know how lock
statement works but it seems I don't ... I'm trying to achieve functionality that enables me adding and deleting rows to/from DataSet
concurrently from separate threads (WinForms project). So one thread is adding new row to DataSet
every some time interval while other thread is deleting row from the same DataSet
. I assum that DataSet
always has some rows to delete - I would like to focus on multithreading issus here. Thread that adds rows to DataSet
works faster then one that deletes rows. For creating new threads I use System.Threading.Timer
class which starts new thread while creating new instance on this class. I don't understand why I still get System.InvalidOperationException
while having lock
statement in my code. Further message is : "Additional information: Cross thread operation detected."
How should I use lock
statement ?
Where exactly should I put lock
statement in my code ?
CODE :
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;
}
}
}
Upvotes: 0
Views: 659
Reputation: 38046
The problem is not with the lock
statement, but with accessing UI control (removing rows from data source) from the thread which is not UI thread.
Actually you do it right when adding rows, so do the same when deleting - use form's Invoke
method in order to execute delegate on the right thread.
Upvotes: 1