3

私は次のコードを持っています:

// 1.
        public void RunSQL(QuerySetup querySetup)
        {
            //querySetup.Users is 10
            for (int i = 1; i <= querySetup.Users; i++)
            {
                querySetup.CurrentUser = i;
                var worker = new BackgroundWorker {WorkerReportsProgress = true};
                worker.DoWork += worker_DoWork;
                worker.RunWorkerCompleted += worker_RunWorkerCompleted;
                worker.RunWorkerAsync(querySetup);
            }
        }


    // 2.
    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        var querySetup = e.Argument as QuerySetup;
        // Doing stuff...
        e.Result = querySetup.CurrentUser;
    }

    // 3.
    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("User " + e.Result.ToString() + " is done.");
    }

私の目標は、最後に次のことを取得することです。

ユーザー1が完了しました

ユーザー2が完了しました

..。

ユーザー10が完了しました

(その特定の順序ではありません)

しかし、私は10倍の「ユーザー10が完了しました」しか得られません。

しかし、なぜ?後で識別できるように、ワーカープロセスに何らかの方法でマークを付ける必要があります。

4

3 に答える 3

4

はい、ここにはquerySetupオブジェクトが1つだけあり、メインループはcurrentUserを継続的に変更します。
すべてのスレッドがその単一のオブジェクトを共有します。

 for (int i = 1; i <= querySetup.Users; i++)
 {
     querySetup.CurrentUser = i;
     ... 
     worker.RunWorkerAsync(querySetup);
 }

基本的な解決策(他のquerySetupメンバーが必要ない場合)

 for (int i = 1; i <= querySetup.Users; i++)
 {
     //querySetup.CurrentUser = i;
     ... 
     worker.RunWorkerAsync(i);
 }
于 2012-09-24T14:43:58.167 に答える
2

QuerySetupのインスタンスは1つだけです。

この1つのインスタンスに現在のユーザーを保存しています。したがって、現在のユーザーは常にループの最後のユーザーになります。

于 2012-09-24T14:44:14.560 に答える
1

ループが終了した後にすべてのワーカーが終了すると、すべてのワーカーに同じグローバル状態(querySetup.CurrentUserその時点で10)が表示されます。

マルチスレッドの最善のアプローチは、スレッド間で状態を共有することではなく(その状態へのアクセスを同期する必要があるため)、代わりに各スレッド関数に独自のデータのコピーを提供することです。この場合、querySetupスレッド関数のデータとして提供する代わりに、提供することを意味しますquerySetup.CurrentUser

于 2012-09-24T14:45:30.347 に答える