1

これはエラーをスローしていませんが、最初のスレッドを実行した後、2番目のスレッドを実行していません。私は何か間違ったことをしていますか?

以下は私のコードです:私のボタンクリック機能:

 private void ImportBothButtonclick(object sender, EventArgs e)
    {
        // Get the currently selected manufacturer from the combo box
        var selected = comboBox.SelectedItem;

        // Do we have one?
        if (selected != null)
        {
            // Extract the combo record
            var val= (ComboBoxItem)selected;

            // Do we have one?
            if (val != null)
            {
                // yes
                // Make this on a seperate thread so that the UI continues to work
                Invoke(new System.Action(() =>
                {
                    button1.Enabled = false;
                    button2.Enabled = false;
                    button3.Enabled = false;
                    var thread = new Thread(DoFunction1);

                    thread.Start(val); 
                }));

                Invoke(new System.Action(() =>
                {
                    button1.Enabled = false;
                    button2.Enabled = false;
                    button3Enabled = false;
                    var thread = new Thread(DoFunction2);

                    thread.Start(val);
                }));

            }
        }

    }
4

3 に答える 3

4

それらのアクションは何もしません。アクションは、現在使用中の同じスレッドで呼び出されます。

スレッドは現在並行して実行されています。これらのスレッドを GUI スレッドではなくシリアルで実行したい場合は、次のようにすることができます。

これは非タスク バージョンです。

// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;

new Thread(() =>
{
    DoFunction1();
    DoFunction2();

    // execute this on the gui thread. (winforms)
    this.Invoke(new Action( delegate
    {
        button1.Enabled = true;
        button2.Enabled = true;
        button3.Enabled = true;
    }));

}).Start();

それらを並行して実行したいが、完了するまで待つ場合:

// not allowed on a non-gui thread.
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;

new Thread(() =>
{
    ManualResetEvent wait1 = new ManualResetEvent(false);
    ManualResetEvent wait2 = new ManualResetEvent(false);

    ThreadPool.QueueUserWorkItem((state) =>
        {
            DoFunction1();
            wait1.Set();
        });

    ThreadPool.QueueUserWorkItem((state) =>
        {
            DoFunction2();
            wait2.Set();
        });

    ManualResetEvent.WaitAll(new WaitHandle[] { wait1, wait2 });

    this.Invoke(new Action( delegate
        {
            // execute this on the gui thread. (winforms)
            button1.Enabled = true;
            button2.Enabled = true;
            button3.Enabled = true;
        }));
}).Start();

しかし、これはタスクを使用してより簡単にすることができます。タスク並列処理 (タスク並列ライブラリ) http://msdn.microsoft.com/en-us/library/dd537609.aspx

于 2013-09-09T10:57:30.303 に答える
2

あなたが観察している正確な問題は何ですか?

あなたが現在述べていることによると、問題は「最初のスレッドの後に2番目のスレッドが実行されない」ことにあります。

では、これにお答えしましょう。

あなたのコードはほとんど問題ありません。あなたは1 つの重要なことを見落としています: あなたのコード "new thread / thread.start()" は実際に新しいスレッドを開始し、そのスレッドが実行または完了するのを待ちません。

行:

new thread(f1).Start()
new thread(f2).Start()

「スレッド1でF1を実行してから、スレッド2でF2を実行」しません。代わりに、「スレッド 1 で F1 の実行を開始し、すぐにスレッド 2 で F2 の実行を開始します」。

F1 が完全に終了した後にのみ F2 を実行するには、何らかの方法で 2 つを「チェーン」する必要があります。

  • 単純な「アジェンダ」メソッドを作成して、代わりに実行できます。

    private void doAllTasks()
    { 
        f1();
        f2();
    }
    
    new thread(doAllTasks).Start()
    
  • ラムダを介してオンザフライで「連鎖」することができます。これは実質的に上記と同じです。

    new thread(() => { f1(); f2(); ).Start()
    
  • 実際には両方をすぐに実行できますが、F1 のスレッドが終了するまでF2 を[待機] に参加させます。

    var th1 = new thread(f1);
    var th2 = new thread(() => {th1.Join(); f2();} ) 
    
    th1.Start();
    th2.Start();
    // note that this code is NOT perfect, there's some error handling to do here, etc..
    

または、 Sheridan's answerに見られるように、TPL フレームワークのようなすべての素敵できれいなラッパーを試すことができます。

もちろん、他の新しいスレッドが実行している内部から UI 要素に触れる場合は注意が必要です。Sheridanの回答は、TPLの方法ですでにカバーしています。手動では、Invoke/BeginInvoke を使用して UI 関連のコードを UI スレッドに戻す必要があります。現在のコードでは既にそれを持っていますが、_Click ハンドラー メソッドは明らかに既に UI スレッドで実行されているため、その場所では必要ありません。

したがって、現在の例は次のように縮小できます。

private void ImportBothButtonclick(object sender, EventArgs e)
{
    var selected = comboBox.SelectedItem;

    if (selected != null)
    {
        var val= (ComboBoxItem)selected;

        if (val != null)
        {
            // no Invoke needed, "button_click" handlers
            // are already on UI thread, so touching UI things is OK
            button1.Enabled = false;
            button2.Enabled = false;
            button3.Enabled = false;

            // starting a new thread also does not need Invoke
            var thread = new Thread(DoAllFunctions);
            thread.Start(val); 
        }
    }
}

private void DoAllFunctions(object something)
{
    DoFunction1(something);
    DoFunction2(something);

    // button1.Enabled = true; - cannot do it here because they are UI
    // button2.Enabled = true; - and DoAll is run from other thread.
    // button3.Enabled = true; - you must bounce that back to UI thread.

    LetTheUIKnowJobsAreFinished(); // <- performed here
}

private void LetTheUIKnowJobsAreFinished()
{
    Invoke(new Action(()=>{
        button1.Enabled = true;
        button2.Enabled = true;
        button3.Enabled = true;
    });
}

また、最後の注意として、System.ComponentModel から参照してください。BackgroundWorkerすべてのスレッドクロスを非常に簡単にする、非常に優れたイベント/コールバックのセットがあります。

(ところで、もう一度言わせてください: このコードは使用できません。これは単なるスケッチです。タイプミス、コロンの欠落、try-catch-whatever の欠落などがあります!)

于 2013-09-09T11:05:21.727 に答える