0

我阅读了有关线程池的文档,并编写了测试代码以将来自不同线程的数据加载到两个网格中。但有时,只有一个网格填充,而另一个保持为空。有时一切都很好。为什么?当我使用 waitall 时出现此异常:不支持 STA 线程上的多个句柄的 WaitAll。

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

    }
4

2 回答 2

1

WaitAll[STAThread]在标记为WinForms 应用程序中的主线程的线程中不允许出现这种情况。我建议不要使用,WaitHandle而是可以通过调用通知主线程。像这样声明一个函数:

void dataready
{
    dataGridView1.DataSource = ...
}

并在工作线程结束时设置事件调用此函数:

Invoke(new Action(dataready));

这应该可以解决问题。

于 2013-01-01T09:37:52.953 回答
0

UI 控件是在具有单线程单元 (STAThread) 的线程上创建的。

原因是 Windows 应用程序使用 [STAThread] 属性进行归因。

在这里阅读更多

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

你可以尝试的是

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

我没有测试过,但我认为它应该可以工作。

为什么您的代码失败:

您已经从正在执行按钮单击事件的线程中启动了两个线程池线程。但是,每当您需要将从这些线程接收到的数据更新到 UI 时,您应该使用 Invoke 来更新 UI 中的数据。如果不使用 Invoke 更新 UI 上的数据,则会出现 Invalid cross thread access 错误。

要从另一个线程更新 UI,请在此处阅读答案

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

于 2013-01-01T09:33:49.413 回答