一、TLS
執行緒本地存盤(Thread Local Storage),字面意思就是專屬某個執行緒的存盤空間,變數大體上分為全域變數和區域變數,一個行程中的所有執行緒共享地址空間,這個地址空間被劃分為幾個固有的區域,比如堆疊區,全域變數區等,全域變數存盤在全域變數區,虛擬地址固定;區域變數存盤在堆疊區,虛擬地址不固定,每個執行緒都有自己的堆疊空間,區域變數就存盤在堆疊空間里面,雖然這個區域變數是與執行緒相聯系的,但是這個區域變數不能在不同的函式堆疊中互相直接訪問,但TLS可以,概括來講,TLS是屬于執行緒的“區域變數”,作用域為執行緒作用域,而不像全域變數為全域作用域,區域變數為區域作用域,因為這個變數獨屬于這個執行緒,所以這個變數是執行緒安全的,
二、.NET中相關的類——ThreadLocal
代碼更直觀,請看下面的代碼:
1 static void Main(string[] args) 2 { 3 ThreadLocal<int> threadLocal = new ThreadLocal<int>(); 4 //在主執行緒這個變數值為1 5 threadLocal.Value = https://www.cnblogs.com/hkfyf/p/1; 6 new Thread(() => Console.WriteLine($"托管執行緒ID:{Thread.CurrentThread.ManagedThreadId} 值為:{threadLocal.Value++}")).Start(); 7 new Thread(() => Console.WriteLine($"托管執行緒ID:{Thread.CurrentThread.ManagedThreadId} 值為:{threadLocal.Value++}")).Start(); 8 new Thread(() => Console.WriteLine($"托管執行緒ID:{Thread.CurrentThread.ManagedThreadId} 值為:{threadLocal.Value++}")).Start(); 9 Console.WriteLine($"主執行緒ID:{Thread.CurrentThread.ManagedThreadId} 值為:{threadLocal.Value}"); 10 }
輸出結果如下:

可以看見每個這個變數的值對于每個執行緒來說都是獨立的,一個執行緒對這個變數的修改只會影響本執行緒的讀取,每個執行緒都有一份拷貝,
有什么用呢?或者使用場景是什么呢?我覺得就是一句話——當每個執行緒都需要一個唯一的變數的時候,
比如早期版本的ASP.NET,每個執行緒處理一個Http請求,在處理這個Http請求的執行緒中,這個HttpContext在這個執行緒中是唯一的,所以在每個函式中都可以呼叫HttpContext.Current獲得當前Http請求背景關系物件,為了加深理解,請看下面的代碼
1 public class ConsoleContext 2 3 { 4 5 private static ThreadLocal<ConsoleContext> _tlsCCT = new ThreadLocal<ConsoleContext>(); 6 7 private string _consoleName; 8 9 public string ConsoleName { get => _consoleName; } 10 11 public static ConsoleContext Current { get => _tlsCCT.Value; } 12 13 public ConsoleContext(string consoleName) 14 15 { 16 17 _consoleName = consoleName; 18 19 _tlsCCT.Value = https://www.cnblogs.com/hkfyf/p/this; 20 21 } 22 23 public static void ResetContext() => _tlsCCT.Value = https://www.cnblogs.com/hkfyf/p/null; 24 25 } 26 27 public static void Excute() 28 29 { 30 31 Thread.Sleep(1000 * new Random(DateTime.Now.Millisecond).Next(5,10)); 32 33 Console.WriteLine("進入PrintName()"); 34 35 PrintName(); 36 37 } 38 39 public static void PrintName() 40 41 { 42 43 var name = ConsoleContext.Current.ConsoleName; 44 45 Console.WriteLine($"當前托管執行緒ID:{Thread.CurrentThread.ManagedThreadId} name:{name}"); 46 47 } 48 49 static void Main(string[] args) 50 51 { 52 53 while (true) 54 55 { 56 57 var name = Console.ReadLine(); 58 59 ThreadPool.QueueUserWorkItem(state => 60 61 { 62 63 Console.WriteLine($"當前托管執行緒ID:{Thread.CurrentThread.ManagedThreadId} name:{name}"); 64 65 new ConsoleContext(name); 66 67 Excute(); 68 69 ConsoleContext.ResetContext(); 70 71 }); 72 73 } 74 75 }
簡單來說,我模擬了一個Web服務器的行為,監聽請求(在這里是監聽鍵盤輸入),若沒有請求過來,服務器程式阻塞,若有請求過來(在這里是鍵盤輸入),服務器回應請求,生成當前請求背景關系,并生成一個TLS變數,然后執行Excute函式(相當HttpContext流入處理管道),最后清空TLS變數中的值,因為該執行緒是執行緒池中的執行緒,會被復用用于處理其他請求,不清空TLS會生成臟資料,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/6415.html
標籤:C#
上一篇:邏輯式編程語言極簡實作(使用C#) - 4. 代碼實作(完結)
下一篇:csharp: Emgu.CV.OCR and Tesseract.OCR Optical Character Recognition
