Thread Local Storage (TLS)



実際にゲームサーバを実装すると、上図のような状況になります.
各セクションには複数の従業員(Threed)がおり、他のセクションと協力することもできます.
この場合、Race Conditionが発生しないように、すべてのタスクをロックします.これは本当に正しい選択ですか?

MMORPGがboss mambladeを行うと、数百人のプレイヤーが特定の領域に集まり、クライアントセッションでゲームロジックで大量のパケットを送信する.この場合ロックを使うとどうなりますか?
ロックは互いに反発する概念である.つまり、1人の従業員だけが仕事を処理できるということです.
すなわち,せっかくマルチスレッド環境を選択したのに,すべてのタスクを1人で処理するためにペナルティエリアを実施した.逆に,ドアをロックする過程でドアをロックする時間とドアを開く時間を考慮すると,マルチスレッドの損失に等しい.
マルチスレッド環境では、パブリックスペースのデータにアクセスすると問題が発生します.ロックも、共通空間の1つのスレッドにのみアクセスするために使用されます.

だから私たちはHeapエリアとデータエリアのようにグローバル空間ですが!
Thread Local Storage(スタックなど)は、スレッドごとに割り当てられる記憶領域であり、TLSと略称される.
 class Program
    {
        static ThreadLocal<string> threadName = new ThreadLocal<string>();
        
        static void Whoami()
        {
            threadName.Value = $"My name is {Thread.CurrentThread.ManagedThreadId}";

            Thread.Sleep(1000); 

            Console.WriteLine(threadName.Value);
        }

        static void Main(string[] args)
        {
            Parallel.Invoke(Whoami, Whoami, Whoami, Whoami, Whoami); // 여기다 넣어주는 Action만큼 Task를 만들어준다. 
        }
    }
ThreadLocal<>を使用してTLSを作成できます.
Parallel.Invokeでは,パラメータとして受信した動作と同じTaskを自動的に生成する関数である.
TLSに格納されているthreadNameを画面に出力した場合?

このようにして,各Threedの名前がうまく出力されていることが分かる.
でも.
        static string threadName; 
        
        static void Whoami()
        {
            threadName = $"My name is {Thread.CurrentThread.ManagedThreadId}";

            Thread.Sleep(1000); 

            Console.WriteLine(threadName);
        }
次のコードを変更して、threadNameを静的変数であるためデータ領域に格納します.

このように,現在はThreedのIDだけが5回出力されている.これは、TLSに格納される各スレッドのデータではなく、共通空間に格納されるデータであるからである.
修正コードは次のとおりです.
        static ThreadLocal<string> threadName = new ThreadLocal<string>(() => 
        { return $"My name is {Thread.CurrentThread.ManagedThreadId}"; });
        
        static void Whoami()
        {
            bool IsRepeat = threadName.IsValueCreated; 

            if(IsRepeat)
            {
                Console.WriteLine($"My name is {threadName.Value}" + " (repeat)");
            } 
            else
                Console.WriteLine($"My name is {threadName.Value}");
        }

        static void Main(string[] args)
        {
            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.SetMaxThreads(2, 2); 

            Parallel.Invoke(Whoami, Whoami, Whoami, Whoami, Whoami); // 여기다 넣어주는 Action만큼 Task를 만들어준다. 
        }
Func依頼はnew ThreadLocal<>のパラメータを使用して受信できます.
この機能を利用して、TLSが新しく作成された場合、ThreadLocal.戻り値をValueに入れます.
の世話を
ThreadLocal.IsValueCreatedは、値が初期化されている場合、trueとfalse(初期化されていない場合)を返します.
この場合、SetMinThreadsおよびSetMaxThreadsを使用して、Threedfullから抽出されたThreedの数を最小1個、最大2個に制限する.

上の画像から、作業が完了したスレッドがWhoami関数を返して実行することがわかります.