开发者

ThreadLocal Aggregations and Task Parallel Library

Why do i get different result with the following to sections of code

Code Sample 1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadLocalTasks
{
    class Program
    {
        static void Main(string[] args)
        {

            ThreadLocal<int> aggregrations = new ThreadLocal<int>();
            Task<int>[] tasks = new Task<int>[10];

            for (int i = 0; i < tasks.Length; i++)
            {
                aggregrations.Value = 0;
                int tempi = i;
                tasks[tempi] = new Task<int>(() =>
                {
                    int temp = 0;
                    for (int j = 1; j <= 3; j++)
                    {
                        temp += j;
                    }
                    aggregrations.Value = temp;
                    return aggregrations.Value;
                });

            }

            tasks.ToList().ForEach(x => {
               开发者_如何学运维 x.Start();
            });

            Task.WaitAll(tasks);

            int sum = 0;

            tasks.ToList().ForEach(x =>
            {
                sum += x.Result;
            });

            Console.WriteLine("Sum: {0}", sum);

            Console.WriteLine("Press any key to quit..");
            Console.ReadKey();
        }
    }
}

Sample 2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadLocalTasks
{
    class Program
    {
        static void Main(string[] args)
        {

            ThreadLocal<int> aggregrations = new ThreadLocal<int>();
            Task<int>[] tasks = new Task<int>[10];

            for (int i = 0; i < tasks.Length; i++)
            {
                aggregrations.Value = 0;
                int tempi = i;
                tasks[tempi] = new Task<int>(() =>
                {
                    for (int j = 1; j <= 3; j++)
                    {
                        aggregrations.Value += j;
                    }
                    return aggregrations.Value;
                });

            }

            tasks.ToList().ForEach(x => {
                x.Start();
            });

            Task.WaitAll(tasks);

            int sum = 0;

            tasks.ToList().ForEach(x =>
            {
                sum += x.Result;
            });

            Console.WriteLine("Sum: {0}", sum);

            Console.WriteLine("Press any key to quit..");
            Console.ReadKey();
        }
    }
}


Why are you even trying to use ThreadLocal storage here instead of just a local variable within the Task? The Task Parallel library may well reuse a thread to execute more than one Task and your thread local storage will get overwritten. In the first example it might work since you aren't resetting it each time a thread is reused but this would be better:

for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = new Task<int>(() =>
            {
                int sum = 0;
                for (int j = 1; j <= 3; j++)
                {
                    sum += j;
                }
                return sum;
            });

        }

Explanation as to what your code actually does:

In you first example you initialize a single thread local value to 0 on the startup thread but you do it multiple times (clearly not what you intended by putting the initialization in the for loop - bug #1). You accumulate in a task-local variable which is good but you then overwrite the thread local value with the result even though that thread-local value may be shared between multiple tasks executing sequentially (e.g. one thread per core) - bug #2. This will cause some tasks to share the same thread local value. Bug #3: when you return the thread local value you get lucky because it will be the same as temp and no other thread can have changed it so it's equivalent to just using a local variable within the task.

In your second example you make the same mistake on initialization. But then you go on to double count values because the thread local value is not reset at the start of each task so if two tasks run on the same thread the first might return 1+2+3 and the second might return 6+1+2+3.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜