yasmuru
yasmuru

Reputation: 1186

Multithreading with Datagridview C#

Here i'm doing one process of checking user names. I've created one datagridview and loadded data from the text file. so the datagridview contains first name and last name of users in first two columns . What i need to do is read those values row by row and find that there is no same name for first and last .These operation is performed in separate class. So i need to get result from that class and show the result to gridview alternatively . It all works fine when i'm using just one thread . But when i'm using more than one thread it just throwing an exception that outofbound exception in gridview reading . Here is my coding :

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();
    }
}

Please suggest me how to use Multithread here ... its just an example .. please explain any other way ..

Upvotes: 2

Views: 6246

Answers (2)

Brian Gideon
Brian Gideon

Reputation: 48949

There are several problems with this code.

  1. You are accessing the DataGridView from a worker thread. This is evident by the first line of code in check. You simply cannot do this.

  2. You defined the variables i, j, l, and presumably k and m (though I do not see them declared anywhere) as static. The consequence is that each worker thread will be working with the same values and stepping on each other's toes. It is a bigger problem for i since it actually is being accessed from the worker thread. The others are accessed from anonymous delegate which is marshaled onto the UI thread. Still, that is probably going to cause a lot of confusion because the order in which anonymous delegates are getting executed is unpredictable.

  3. You are calling Invoke from the worker thread. This is not a problem by itself. But, considering that you are mashaling all of the useful work back onto the UI thread it is rather pointless. Think about it. You went to all that work to use a worker thread and then you marshal everything back onto the UI thread anyway. You now have a solution that is worse than had you not used any worker threads at all.

  4. This is not a problem really, but more of a gripe I have. Why bother calling InvokeRequired? You already know that "invoking" is required because you know at development time that this stuff is on a worker thread.

My recommendations are as follows.

  1. Do not use threads at all. It is pointless in this case. The only useful work that can be performed on a another thread is the comparison of the first and last names. That is trivial and can be done just as quickly on the UI thread.

  2. If you really want to use a separate thread then you have to read the values from the DataGridView on the UI thread and put them in a separate data structure; one that is safe to use from another thread. It would be better to maintain this data structure in tandem with the DataGridView that way when it comes time to initiate your long running operation you will not need to read the grid since you already have the data copied into this separate data structure.

Upvotes: 2

ClotzA
ClotzA

Reputation: 161

  1. Use the lock statement to prevent different threads to run the same code at the same time. You would need a reference to use as an identifier for the lock. It's common to create a simple object that is used only for the locking:

    static object sync = new Object();
    lock (sync) 
    {
      // do multithreaded stuff here
    }
    
  2. The UI is not multithreading friendly so it's not wise to update the DataGridView directly because it refreshes when a values is being edited. Alter its DataSource and call for an Update when all threads finished work.

    DataSet dataset = dataGridView1.DataSource;
    
    // do threaded operations on dataset
    
    // update the datagrid when threads finish work
    dataGridView1.DataSource = dataset;
    dataGridView1.Update();
    
  3. I noticed in your code runs the same code 3 times instead of splitting your data into 3 parts and updating it independently. Try doing something like this:

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

You could see a different approach using BackgroundThread here:

Nonblocking update to a DataGridView

Upvotes: 0

Related Questions