3

次のコードを実行してスレッドを開始していますが、意図したとおりに開始しません。何らかの理由で、一部のスレッドは同じオブジェクトで開始されます (また、一部のスレッドは開始すらしません)。デバッグしようとすると、問題なく開始されます (コードをステップ実行するために F10 をクリックすると、遅延が追加されます)。

これらは私のフォームアプリの機能です:

private void startWorkerThreads()
{
    int numThreads = config.getAllItems().Count;
    int i = 0;

    foreach (ConfigurationItem tmpItem in config.getAllItems())
    {
        i++;
        var t = new Thread(() => WorkerThread(tmpItem, i));
        t.Start();
        //return t;
    }
}

private void WorkerThread(ConfigurationItem cfgItem, int mul) 
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(10*mul);
    }
    this.Invoke((ThreadStart)delegate()
    {
        this.textBox1.Text += "Thread " + cfgItem.name + " Complete!\r\n";
        this.textBox1.SelectionStart = textBox1.Text.Length;
        this.textBox1.ScrollToCaret();
    });
}

誰でも私を助けることができますか?

4

7 に答える 7

2

スレッドを開始しても、実際にはスレッドが開始されません。代わりに、実行のためにスケジュールします。つまり、ある時点で、スケジュールされたときに実行されるようになります。スレッドのスケジューリングは複雑なトピックであり、OS の実装の詳細であるため、コードで特定のスケジューリングを想定するべきではありません。

また、ラムダで変数をキャプチャしています。それを行うことに関連する問題については、この投稿(キャプチャされた変数に関するセクションがあります)を参照してください。

于 2010-03-18T09:29:46.067 に答える
2

あなたは(私が呼ばれる)ラムダエラーに出くわします。

ConfigurationItemforeach ループから直接提供します。これは、すべてのスレッドが同じアイテム (最後のアイテム) を取得するという事実につながります。

これを機能させるには、各アイテムの参照を作成し、これを各スレッドに適用する必要があります。

foreach (ConfigurationItem tmpItem in config.getAllItems())
{
        i++;
        var currentI = i;
        var currentItem = tmpItem;
        var t = new Thread(() => WorkerThread(currentItem, currentI));
        t.Start();
        //return t;
}

また、ThreadPool の使用も検討する必要があります。

于 2010-03-18T09:50:31.250 に答える
1

問題があるようです:() => WorkerThread(tmpItem, i)

私は慣れてFunc<>いませんが、.NET 2.0 の匿名デリゲートのように機能するようです。したがって、WorkerThread()メソッドの引数への参照がある場合があります。したがって、それらの値は後で取得されます (スレッドが実際に実行されるとき)。

この場合、すでにメインスレッドの次の繰り返しにいる可能性があります...

代わりにこれを試してください:

var t = new Thread(new ParametrizedThreadStart(WorkerThread));
t.Start(new { ConfigurationItem = tmpItem, Index = i } );

[編集] その他の実装。将来、新しいパラメーターをスレッドに渡す必要がある場合は、より柔軟です。

private void startWorkerThreads()
{
    int numThreads = config.getAllItems().Count;
    int i = 0;

    foreach (ConfigurationItem tmpItem in config.getAllItems())
    {
            i++;
            var wt = new WorkerThread(tmpItem, i);
            wt.Start();
            //return t;
    }
}
private class WorkerThread
{
    private ConfigurationItem _cfgItem;
    private int _mul;
    private Thread _thread;
    public WorkerThread(ConfigurationItem cfgItem, int mul) {
        _cfgItem = cfgItem;
        _mul = mul;
    }
    public void Start()
    {
        _thread = new Thread(Run);
        _thread.Start();
    }
    private void Run()
    {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(10 * _mul);
        }
        this.Invoke((ThreadStart)delegate()
        {
            this.textBox1.Text += "Thread " + _cfgItem.name + " Complete!\r\n";
            this.textBox1.SelectionStart = textBox1.Text.Length;
            this.textBox1.ScrollToCaret();
        });
    }
}
于 2010-03-18T09:59:46.600 に答える
0

エラーはどこかにあると思います。デバッグに役立つヒントを次に示します。

  1. 各スレッドに含まれる名前を付け、構成アイテム名の代わりにスレッド名を表示します。

    this.textBox1.Text + = "Thread" + Thread.Current.Name + "Complete!\ r \ n";

  2. config.getAllItems()の内容を表示します。一部のアイテムが同じ名前である可能性があります(重複)

===========

WinFormsを使用したマルチスレッドに関する追加情報は次のとおりです。

  1. 新しいスレッドを直接作成しないでください。代わりにThreadPoolを使用してください。

    ThreadPool.QueueUserWorkItem(state => {WorkerThread(tmpItem、i);});

  2. 本当にスレッドを作成したい場合は、this.BeginInvokeの代わりにthis.BeginInvokeを使用してください。ワーカースレッドを呼び出すと、より早く終了します=>同時スレッドが少なくなります=>グローバルパフォーマンスが向上します
  3. ループ内でThread.Sleepを呼び出さず、大きなスリープを実行します。Thread.Sleep(10 * mul * 100);

これがお役に立てば幸いです。

于 2010-03-18T09:49:10.457 に答える
0

手動でスレッドを生成する必要がありますか (これはかなりコストのかかる作業です)。代わりに ThreadPool に切り替えてみてください。

于 2010-03-18T09:29:50.157 に答える
0

スレッドが呼び出されたのと同じ順序で実行されると想定することはできません。強制しない限り、それらの間に依存関係が生じます。

だから本当の質問は - あなたの目標は何ですか?

于 2010-03-18T09:31:11.977 に答える
0

皆さんのお陰で!

スレッドプールを実装したばかりで、それは魅力のように機能しました-一度に多くのスレッドを生成しないという追加のボーナスがあります。

他のソリューションも見ていきますが、今回はスレッドプールを使用することで、構成が多すぎるボゾを手動でチェックする必要がなくなります;)

于 2010-03-18T10:41:48.600 に答える