0

スレッド プーリングに関するドキュメントを読み、異なるスレッドから 2 つのグリッドにデータをロードするテスト コードを作成しました。ただし、場合によっては、1 つのグリッドだけがいっぱいになり、もう 1 つのグリッドが空のままになることがあります。そして時々すべてが大丈夫です。なんで?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-support.aspx

あなたが試すことができるのは

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

私はテストしていませんが、うまくいくはずだと思います。

コードが失敗する理由:

ボタン クリック イベントを実行していたスレッドから 2 つのスレッドプール スレッドを開始しました。ただし、これらのスレッドから受信したデータを UI に更新する必要がある場合は常に、Invoke を使用して UI のデータを更新する必要があります。Invoke を使用して UI 上のデータを更新しないと、Invalid cross thread access エラーが発生します。

別のスレッドから UI を更新するには、ここで回答を読んでください

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

于 2013-01-01T09:33:49.413 に答える