从不同的线程并发地在DataSet中添加和删除行

本文关键字:DataSet 添加 删除行 线程 并发 | 更新日期: 2023-09-27 17:54:48

我以为我知道lock语句是如何工作的,但似乎我不知道……我试图实现的功能,使我能够添加和删除行/从DataSet从单独的线程并发(WinForms项目)。因此,一个线程每隔一段时间间隔向DataSet添加新行,而另一个线程从相同的DataSet删除行。我假设DataSet总是有一些行要删除-我想在这里关注多线程问题。添加行到DataSet的线程比删除行更快。对于创建新线程,我使用System.Threading.Timer类,它在创建新实例时启动新线程。我不明白为什么我仍然得到System.InvalidOperationException,而在我的代码中有lock语句。进一步的消息是:"附加信息:检测到交叉线程操作。"

如何使用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;
    }
}
}

从不同的线程并发地在DataSet中添加和删除行

问题不在于lock语句,而在于从非UI线程的线程访问UI控件(从数据源中删除行)。

实际上你在添加行时这样做是正确的,所以在删除时也这样做-使用表单的Invoke方法以便在正确的线程上执行委托