KRR
KRR

Reputation: 505

ThreadPool.QueueUserWorkItem inside foreach use same dataset

In the function below always the same user object is passed to the DoRestCall method

(I do have logging in the DoRestCall method and it has the same first data in the user object) Do I need to use Parallel.ForEach instead of Threadpool

private void CreateUser(DataServiceCollection<User> epUsers)
{
    foreach (User user in epUsers)
    {
        try
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(f =>
            {
                DoRestCall(string.Format("MESSAGE-TYPE=UserEnrollmentCreate&PAYLOAD={0}",
                                         GenarateRequestUserData(user)), true);
            }));
        }
        catch (Exception ex)
        {
            _logger.Error("Error in CreateUser " + ex.Message);
        }
    }
}

Upvotes: 0

Views: 1186

Answers (1)

alsed42
alsed42

Reputation: 1216

The problem is how loop variables are handled when used in a lambda expression or anonymous methods. The lambda expression sees the current value of the loop variable at the time the lambda is executed. I believe this behaviour was changed in C# 5.0, but haven't tried it yet.

You need to store the current user in a variable inside the foreach loop and use that instead of the loop variable (also, your try / catch doesn't catch any exceptions inside your WaitCallback, see fix below):

foreach (User user in epUsers)
{
    User currentUser = user;
    ThreadPool.QueueUserWorkItem(new WaitCallback(f =>
    {
        try
        {
            DoRestCall(string.Format("MESSAGE-TYPE=UserEnrollmentCreate&PAYLOAD={0}",
                                     GenarateRequestUserData(currentUser)), true);
        }
        catch (Exception ex)
        {
            _logger.Error("Error in CreateUser " + ex.Message);
        }
    }));
}

Upvotes: 3

Related Questions