2

在这里,我正在做一个检查用户名的过程。我创建了一个数据网格视图并从文本文件中加载了数据。所以 datagridview 在前两列中包含用户的名字和姓氏。我需要做的是逐行读取这些值,发现 first 和 last 没有相同的名称。这些操作在单独的类中执行。所以我需要从该类中获取结果并将结果显示给 gridview。当我只使用一个线程时,一切正常。但是,当我使用多个线程时,它只会在 gridview 阅读中引发出站异常。这是我的编码:

static int i, j=0, l=0,k=0,m=0;

public void check()
{ 
    for (i = 0; i < dataGridView1.Rows.Count ; i++)
    {
        if (InvokeRequired)
        {
            Invoke(new UpdateDelegate(delegate
                {
                    if (i == 0 && j==0)
                    {
                        DataGridViewColumn col = new DataGridViewTextBoxColumn();
                        col.HeaderText = "Status";
                        int colIndex = dataGridView1.Columns.Add(col);
                        dataGridView1.Rows[i].Cells[colIndex].Value = "Process Started";
                        j = 1;
                    }
                    else
                    {
                        dataGridView1.Rows[i].Cells[3].Value = "process Started";            
                    }
                }));
        }

        if (InvokeRequired)
        {
            Invoke(new UpdateDelegate(delegate 
                { 
                    Process obj_reg = new Process(dataGridView1.Rows[i].Cells[1].Value.ToString(),dataGridView1.Rows[i].Cells[2].Value.ToString());
                    string res = obj_reg.register();
                    Thread.Sleep(500);
                    if (res.Contains("success"))
                    {
                        if (i == 0 && k==0)
                        {
                            DataGridViewColumn col = new DataGridViewTextBoxColumn();
                            col.HeaderText = "Result";
                            int colIndex = dataGridView1.Columns.Add(col);
                            dataGridView1.Rows[i].Cells[colIndex].Value = "Ya its different";
                            dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Green;
                            k = 1;
                        }
                        else 
                        {
                            dataGridView1.Rows[i].Cells[4].Value = "Ya its different";                              
                            dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Green;
                        }
                    }
                    else
                    {
                        if (i == 0 && m == 0)
                        {
                            DataGridViewColumn col = new DataGridViewTextBoxColumn();
                            col.HeaderText = "Result";
                            int colIndex = dataGridView1.Columns.Add(col);
                            dataGridView1.Rows[i].Cells[colIndex].Value = "No its same";
                            dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Red;
                            m = 1;
                        }
                        else
                        {
                            dataGridView1.Rows[i].Cells[4].Value = "No its same";
                            dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Red;

                        }
                    }
                }));
        }
    }
}

public void Button1_Click(Object sender, EventArgs e)
{
    Thread[] threads = new Thread[3];
    for (int l = 0; l < 3; l++)
    {
        threads[l] = new Thread(new ThreadStart(check));
    }
    foreach (Thread t in threads)
    {
        t.Start();
    }
}

请建议我如何在这里使用多线程......它只是一个例子..请解释任何其他方式..

4

2 回答 2

2

这段代码有几个问题。

  1. 您正在DataGridView从工作线程访问 。这从 中的第一行代码就可以看出check。你根本无法做到这一点。

  2. 您将变量ijl和 可能km(尽管我没有看到它们在任何地方声明)定义为静态的。结果是每个工作线程都将使用相同的值并相互踩踏。这是一个更大的问题,i因为它实际上是从工作线程访问的。其他的则从编组到 UI 线程上的匿名委托访问。尽管如此,这可能会引起很多混乱,因为匿名委托的执行顺序是不可预测的。

  3. 您正在Invoke从工作线程调用。这本身不是问题。但是,考虑到您正在将所有有用的工作重新分配到 UI 线程上,这是毫无意义的。想想看。您进行了所有工作以使用工作线程,然后无论如何都将所有内容编组回 UI 线程。您现在有了一个比根本不使用任何工作线程更糟糕的解决方案。

  4. 这真的不是问题,但我有更多的抱怨。为什么要打来电话InvokeRequired?您已经知道“调用”是必需的,因为您在开发时就知道这些东西在工作线程上。

我的建议如下。

  1. 根本不要使用线程。在这种情况下是没有意义的。可以在另一个线程上执行的唯一有用的工作是比较名字和姓氏。这是微不足道的,可以在 UI 线程上快速完成。

  2. 如果您真的想使用单独的线程,那么您必须从 UI 线程上读取值DataGridView并将它们放在单独的数据结构中;一个可以从另一个线程安全使用的线程。当需要启动长时间运行的操作时,最好同时维护这个数据结构,DataGridView因为您已经将数据复制到这个单独的数据结构中,因此您不需要读取网格。

于 2013-08-02T14:20:35.440 回答
0
  1. 使用该lock语句可以防止不同的线程同时运行相同的代码。您需要一个引用来用作锁的标识符。创建一个仅用于锁定的简单对象是很常见的:

    static object sync = new Object();
    lock (sync) 
    {
      // do multithreaded stuff here
    }
    
  2. 不是多线程友好的UI,因此直接更新它是不明智的,DataGridView因为它会在编辑值时刷新。更改它DataSource并调用Update所有线程何时完成工作。

    DataSet dataset = dataGridView1.DataSource;
    
    // do threaded operations on dataset
    
    // update the datagrid when threads finish work
    dataGridView1.DataSource = dataset;
    dataGridView1.Update();
    
  3. 我注意到在您的代码中运行相同的代码 3 次,而不是您的数据分成 3 部分并独立更新。尝试做这样的事情:

    threads[l] = new Thread(new ThreadStart(()=>check( startPosition, endPosition));
    

您可以在这里看到不同的方法BackgroundThread

对 DataGridView 的非阻塞更新

于 2013-08-02T12:37:57.910 回答