开发者

Task.ContinueWith not working how I expected

Consider the following code. I am starting with a task that does nothing, and then using ContinueWith() to start 10 calls to a method that increments a counter.

When I run this program, it prints "0", indicating that the increment() method hasn't been called at all. I was expecting it to be called 10 times, since that's how many times I called ContinueWith().

If I uncomment the "Thread.Sleep(20)" line, then it prints "10" as expected.

This happens in either release or debug mode. My system is a core 2 quad with hyperthreading (8 logical cores) running Windows 7 x64.

I assume I have some kind of fundamental misunderstanding about how Task.ContinueWith() works....

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main()
        {
            using (var t开发者_如何学Cask = Task.Factory.StartNew(()=>{}))
            {
                for (int i = 0; i < 10; ++i)
                {
                    task.ContinueWith(_=> increment());
                    // Thread.Sleep(20);  // Uncomment to print 10 instead of 0.
                }

                task.Wait();
            }

            // This prints 0 UNLESS you uncomment the sleep above.
            Console.WriteLine(counter); 
        }

        static void increment()
        {
            Interlocked.Increment(ref counter);
        }

        private static int counter;
    }
}

Can anyone shed any light on what's going on here?


The reason is simple: You wait on the task that is already finished. What you really want is to wait for the ten tasks you created in the loop:

var tasks = new List<Task>();
for (int i = 0; i < 10; ++i)
{
    tasks.Add(task.ContinueWith(_=> increment()));
}

Task.WaitAll(tasks.ToArray());


Sure. You're printing out the value when the initial task has completed - you're not waiting for the continuation to occur. In other words, when the initial task completes, 11 things happen:

  • 10 new tasks start executing, each incrementing the counter
  • You print out the counter

You could effectively chain all these together if you want:

task = task.ContinueWith(_=> increment());

Then when the original task finishes, one incrementer will fire. When that finishes, the next incrementer will fire. When that finishes [...]. And when the final incrementer has finished, your Wait call will return.


If you change the main body as follows:

        using (var task = Task.Factory.StartNew(() => { }))
        {
            var t = task;
            for (int i = 0; i < 10; ++i)
            {
               t = t.ContinueWith(_ => increment());
                // Thread.Sleep(20);  // Uncomment to print 10 instead of 0.
            }

            t.Wait();
        }

You will get 10 without sleeping. The main change is t = t.ContinueWith(...) and t is necessary because you're not allowed to change the using() variable.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜