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

是的,这里只有 1 个 querySetup 对象,主循环会不断改变 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 实例。

您将当前用户存储在这一实例上。因此,当前用户将始终是您循环中的最后一个用户。

于 2012-09-24T14:44:14.560 回答
1

如果您的所有工作人员在循环完成后完成,那么他们都将看到相同的全局状态querySetup.CurrentUser,此时为 10。

多线程的最佳方法不是在线程之间共享状态(因为这会迫使您同步访问该状态),而是为每个线程函数提供自己的数据副本。在这种情况下,这意味着querySetup您不提供线程函数的数据,而是提供querySetup.CurrentUser

于 2012-09-24T14:45:30.347 回答