はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】ThreadStaticを利用してスレッドによって異なるインスタンスが生成される静的フィールドを作成する

はじめに

今回はThreadStaticを利用してスレッドによって異なるインスタンスが生成される静的フィールドを作成する方法を紹介したいと思います。

learn.microsoft.com

やり方

[ThreadStatic]を静的フィールドにつけると、スレッドごとにインスタンスが作成されるようになります。

public class Program
{
    [ThreadStatic] private static int ThreadStaticNum;
    private static int StaticNum;
    
    public static void Main(string[] args)
    {
        ThreadStaticNum = 1;
        StaticNum = 1;
        
        // [1] ThreadStaticNum : 1
        // [1] StaticNum : 1
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ThreadStaticNum : {ThreadStaticNum}");
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] StaticNum : {StaticNum}");

        // 別スレッドに移動させる
        var task = Task.Run(() =>
        {
            // [5] ThreadStaticNum : 0
            // [5] StaticNum : 1
            Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ThreadStaticNum : {ThreadStaticNum}");
            Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] StaticNum : {StaticNum}");

            ThreadStaticNum = 2;
            StaticNum = 2;
            
            // [5] ThreadStaticNum : 2
            // [5] StaticNum : 2
            Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ThreadStaticNum : {ThreadStaticNum}");
            Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] StaticNum : {StaticNum}");
        });

        task.Wait();
        
        // [1] ThreadStaticNum : 1
        // [1] StaticNum : 2
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ThreadStaticNum : {ThreadStaticNum}");
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] StaticNum : {StaticNum}");
    }
}

初期値をつけてはダメ

CA2019:ThreadStatic フィールドでインライン初期化を使用しないでください

ThreadStaticAttributeフィールドは、インライン初期化では使用せず、または static (Visual Basic では Shared) コンストラクターで明示的に初期化しないでください。 static コンストラクターは、static 型 のコンストラクターを実行するスレッドのフィールドのみを初期化します。

CA2019: 'ThreadStatic' フィールドにインライン初期化をしないでください - .NET | Microsoft Learn

// NG
class C
{
    [ThreadStatic]
    private static Object obj = new();
}
// OK
class C
{
    [ThreadStatic]
    private static Object obj;

    static void S1()
    {
        obj ??= new Object();
    }
}

staticでないフィールドはダメ

CA2259: ThreadStatic が静的フィールドでのみ使用されていることを確認してください

ThreadStaticAttributeは、フィールドの値がスレッドごとに一意であることを示し、static フィールド (Visual Basic では Shared) にのみ影響します。 インスタンス フィールドに適用した場合、 属性は動作に影響しません。

CA2259: 'ThreadStatic' が静的フィールドでのみ使用されていることを確認する - .NET | Microsoft Learn

// NG
class C
{
    [ThreadStatic] private string ThreadStaticMessage;
}
// OK
class C
{
    [ThreadStatic] private static string ThreadStaticMessage;
}