为什么C#ThreadLocal在TPL中没有按预期工作?

时间:2017-10-15 10:02:52

标签: c# multithreading thread-safety task-parallel-library

无法理解一本书中的一个例子来自apress,讨论了在TPL中使用任务构造的一个滥用的threadlocal案例。

为什么它的数量不会超过预期的结果?

有没有人可以对下面程序的程序流程进行更详细的解释,哪一行立即执行,哪些行在时间上同步?执行的顺序和顺序?

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

namespace Listing_05 {

class BankAccount {
    public int Balance {
        get;
        set;
    }
}

class Listing_05 {

    static void Main(string[] args) {

        // create the bank account instance
        BankAccount account = new BankAccount();

        // create an array of tasks
        Task<int>[] tasks = new Task<int>[10];

        // create the thread local storage
        ThreadLocal<int> tls = new ThreadLocal<int>(() => {
            Console.WriteLine("Value factory called for value: {0}",
               account.Balance);
            return account.Balance;
        });

        for (int i = 0; i < 10; i++) {
            // create a new task
            tasks[i] = new Task<int>(() => {

                // enter a loop for 1000 balance updates
                for (int j = 0; j < 1000; j++) {
                    // update the TLS balance
                    tls.Value++;
                }

                // return the updated balance
                return tls.Value;

            });

            // start the new task
            tasks[i].Start();
        }

        // get the result from each task and add it to
        // the balance
        for (int i = 0; i < 10; i++) {
            //added by myself to see any hints but still cannot have insights
            Console.WriteLine("task {0} results {1}", i, tasks[i].Result);
            //end of my editing

            account.Balance += tasks[i].Result;
        }

        // write out the counter value
        Console.WriteLine("Expected value {0}, Balance: {1}",
            10000, account.Balance);

        // wait for input before exiting
        Console.WriteLine("Press enter to finish");
        Console.ReadLine();
    }
}

}

使用8核i7 cpu的计算机结果,应为8个线程。运行几次以下是许多执行中的两次。

1st execute

2nd execute

不明白程序如何以这种方式运作和行为

1 个答案:

答案 0 :(得分:2)

任务提供了一种同时运行代码的机制。这并不意味着它们必然会在不同的线程上运行,或者即使使用多个线程也不会重用它们。

不要尝试将线程本地存储与任务一起使用。

备用存储选项是在任务的lambda函数中使用闭包,或者创建一个类并将数据放在该类上,并使用该类的方法作为任务的被调用者。不管怎样,我个人觉得这很清洁。

Hans Passant在评论中也提到Node值得研究的评论(我自己也没有用过,所以不能发表评论)。