2017-10-15 92 views
2

無法理解一本書中來自apress的示例,它講述了TPL中帶有任務構造的threadlocal的濫用案例。爲什麼C#ThreadLocal在TPL任務中不能按預期工作?

爲什麼預期的結果不是10000呢?

任何人都可以給出一個更詳細的解釋下面的程序的程序流,其中行立即執行和一些行異步的時間?執行的順序和順序?

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個線程。多次執行多次執行中有2次執行。

1st execute

2nd execute

不瞭解程序是如何工作的,並以這種方式

+0

查看https://particular.net/blog/the-dangers-of-threadlocal –

+0

是的,我只是谷歌上面的鏈接之前問上面的問題,但也許我是這個線程主題的新手,所以我很難理解程序表現如此的情況。到目前爲止,我的理解是ThreadLocal是僅用於線程的本地數據。任務是聲明性的,它描述了未知工作線程完成的任務。由於10個任務中有一些重用了10個任務中的一些中已經被修改過的相同線程數據,所以線程本地初始化數據將會崩潰,這是未知的嗎?有人可以描述這個例子的執行方式是什麼......應該推遲一些行來運行? – Cuda

+0

@Cuda,你的價值工廠裏有兩個'account.Balance'。兩者都有權返回不同的結果。 – PetSerAl

回答

2

任務提供一種機制來同時運行代碼的行爲。這並不意味着它們必然會在單獨的線程上運行,或者即使使用了多個線程也不會被重用。

不要嘗試使用帶有任務的線程本地存儲。

其他存儲選項是在任務的lambda函數中使用閉包,或者創建一個類並將數據放在該類上,並將該類的方法用作Task的被調用者。無論如何,我個人覺得這樣更清潔。

Hans Passant在評論中也提到AsyncLocal這是值得研究的(我自己沒有用過,所以不能評論)。

+0

所以你的意思是它可以是1個線程同時執行任務或多個線程同時執行任務,不能保證線程的重用,所以不要使用線程本地存儲,它只對單個線程是本地的?什麼應該用於數據存儲的任務? – Cuda

相關問題