Переменная параметр backgroundWorker всегда одинакова?

У меня есть следующий код:

// 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 готов".

Но почему? Мне нужно как-то пометить мой рабочий процесс, чтобы я мог идентифицировать его позже.

3 ответа

Решение

Да, здесь есть только 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);
 }

Существует только один экземпляр QuerySetup.

Вы сохраняете текущего пользователя в этом одном экземпляре. Таким образом, текущий пользователь всегда будет последним в вашем цикле.

Если все ваши работники закончат работу после завершения цикла, то все они увидят одно и то же глобальное состояние querySetup.CurrentUser, что 10 в этот момент.

Наилучший подход к многопоточности - не разделять состояние между потоками (потому что это заставляет вас синхронизировать доступ к этому состоянию), а вместо этого предоставлять каждой функции потока свою собственную копию данных. В этом случае это будет означать, что вместо предоставления querySetup В качестве данных для функции потока вы предоставляете querySetup.CurrentUser

Другие вопросы по тегам