开发者

.Net 4.0 Task thread output is only last item added

I've created what I thought was a simple app using the .Net 4.0 Task class for threading.

Here's the code:

var services = new List<KeyValuePair<int, string>>();
services.Add(new KeyValuePair<int, string>(1, "S1"));
services.Add(new KeyValuePair<int, string>(2, "S2"));
services.Add(new KeyValuePair<int, string>(3, "S3"));

foreach (var service in services)
{
    // if the running tasks don't currently include this service, add it
    if (!htTasks.ContainsKey(service.Key))
    {
        tempTask = Task.Factory.StartNew(() => DoSomeWork(service.Value));
        htTasks.Add(service.Key, tempTask);

        Console.WriteLine("New service added: " + service.Value);
    }
    else
    {
        Console.WriteLine("No new services found");
    }
}

I'm trying to dynamically create threads to do a task based on a list (which will eventually be coming from a database). The actual task is just to print to the console:

public static void DoSomeWork(string threadName)
{
    Console.WriteLine("Work done: " + threadName);
}

However, I get the following output - which suggests only the last thread I add is running:

New Service added: S1
New Service added: S2
New Service add开发者_Go百科ed: S3
Work done: S3
Work done: S3
Work done: S3

Think I must be doing something wrong with creating the threads. Any help appreciated.


You're capturing the loop variable (service) in a lambda expression. Don't do that :) (Follow the link to find out details of what's going on.)

It's easy to fix - copy the loop variable and capture the copy:

foreach (var service in services)
{
    var copy = service;
    // if the running tasks don't currently include this service, add it
    if (!htTasks.ContainsKey(service.Key))
    {
        tempTask = Task.Factory.StartNew(() => DoSomeWork(copy.Value));
        htTasks.Add(service.Key, tempTask);

        Console.WriteLine("New service added: " + service.Value);
    }

    // code as before
}

As a separate note, you haven't declared tempTask anywhere in the code you've shown - personally I wouldn't bother with it - I'd use:

htTasks[service.Key] = Task.Factory.StartNew(() => DoSomeWork(copy.Value));

Note that in C# 5 this "copying" is likely to become unnecessary - Eric Lippert has indicated a few times that the behaviour will probably change to be the more expected "each loop iteration has a separate variable".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜