0

I read documents about thread pooling and I wrote test code to load data into two grids from different threads. Sometimes, though, only one grid fills, and the other remains empty. And sometimes everything's ok. Why? when i use waitall i get this exception:WaitAll for multiple handles on a STA thread is not supported.

       private void button1_Click(object sender, EventArgs e)
       {
          ManualResetEvent[] mre = new ManualResetEvent[2];
            mre[0] = new ManualResetEvent(false);
            multhread ml = new multhread(mre[0]);
            ThreadPool.QueueUserWorkItem(ml.setdatabase,1);           
            mre[1] = new ManualResetEvent(false);
          //  multhread ml2 = new multhread(mre[1]);
            ThreadPool.QueueUserWorkItem(ml.setdatabase2, 2);

            WaitHandle.WaitAll(mre);
            dataGridView1.DataSource = ml.propdt;
            dataGridView2.DataSource = ml.propdt2;
    }
    public DataTable propdt2 { get; set; }
    public void s()
    {
        string constring = "DATA SOURCE=.; database=test;integrated security= true; USER ID=sa;password=123456789";
        SqlCommand com = new SqlCommand();
        SqlConnection con = new SqlConnection(constring);
        com.Connection = con;
        com.CommandText = " select * from imgtable";
        SqlDataAdapter adapt = new SqlDataAdapter(com);
        DataTable dt2 = new DataTable();
        adapt.Fill(dt2);
        propdt2 = dt2;
    }

}
public class multhread
{
    private ManualResetEvent _doneEvent;
    public multhread(ManualResetEvent doevent)
    {
       _doneEvent = doevent;

    }
    public static DataTable dt;
    public static  DataTable dt2;
    public DataTable propdt { get; set; }
    public DataTable propdt2 { get; set; }
    public void setdatabase(Object threadContext)
    {

        string constring = "DATA SOURCE=.; database=test;integrated security= true; USER ID=sa;password=123456789";
        SqlCommand com = new SqlCommand();
        SqlConnection con = new SqlConnection(constring);
        com.Connection = con;
        com.CommandText = " select * from imgtable";
        SqlDataAdapter adapt = new SqlDataAdapter(com);
         dt2 = new DataTable();
        adapt.Fill(dt2);
        propdt2 = dt2;
        _doneEvent.Set();

       // return dt2;

    }
    public void setdatabase2(Object threadContext)
    {

        string constring = "DATA SOURCE=.; database=test;integrated security= true; USER ID=sa;password=123456789";
        SqlCommand com = new SqlCommand();
        SqlConnection con = new SqlConnection(constring);
        com.Connection = con;
        com.CommandText = " select * from imgtable order by id desc ";
        SqlDataAdapter adapt = new SqlDataAdapter(com);
        dt = new DataTable();
        adapt.Fill(dt);
        propdt = dt;
        _doneEvent.Set();

    }
heavy
  • 439
  • 2
  • 5
  • 13
  • Is this code in a web application? – Dinesh Jan 01 '13 at 09:18
  • Are you asking this in an attempt to understand the theory, or is this intended to be actual production code? While it's possible to make simultaneous SQL Server commands work this way, it's definitely not the recommended approach. Are you using .NET 4.5? – RickNZ Jan 01 '13 at 09:33

2 Answers2

1

WaitAll ist not allowed in threads marked as [STAThread] which is the case for the main thread in a WinForms application. I would suggest not to work with WaitHandle instead you could inform your main thread via invoke. Declare a function like this:

void dataready
{
    dataGridView1.DataSource = ...
}

and instad of Setting the Event at the end of your worker thread invoke this function:

Invoke(new Action(dataready));

this should do the trick.

CubeSchrauber
  • 1,199
  • 8
  • 9
0

UI controls are created on a thread with single threaded apartment (STAThread).

The reason is Windows app are attributed using [STAThread] attribute.

Read more here

http://blogs.msdn.com/b/johnlee/archive/2007/07/10/waithandle-waitall-for-multiple-handles-on-a-sta-thread-is-not-supported.aspx

What you can try is

foreach(var a in mre)
{
    a.WaitOne();
}

I have not tested, but i think it should work.

Why your code fails:

You have started two threadpool threads from the thread that was executing the Button click event. But whenever you need to update the data received from those threads to the UI, you should use the Invoke in order to update the data in the UI. If Invoke is not used to update the data on UI, you will get Invalid cross thread access error.

To update UI from another thread read answer here

https://stackoverflow.com/a/661706/448407

Community
  • 1
  • 1
Dinesh
  • 3,652
  • 2
  • 25
  • 35
  • point here is that WaitAll will not work, you need to use this to wait on all the WaitHandles in the array. The code that you have provided needs to be improved to correctly synchronize to bind the grids correctly. What version of framework are you using?? in case of v4 or higher you may want to do this using Task that can help and make your code look very simple – Dinesh Jan 01 '13 at 09:45