SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

.NET Frameworkにおけるマルチスレッドプログラミングの基本

.NETマルチスレッドプログラミング 4:スレッドの優先順位と強制終了

.NET Frameworkにおけるマルチスレッドプログラミングの基本


スレッドローカルストレージ

 スレッドローカルストレージを使うことにより、スレッドごとに別々のデータを格納することができます。格納されたデータはそのスレッドからしか取得あるいは変更できません。

 スレッドローカルストレージを使うには、まずThread.AllocateDataSlotまたはAllocateNamedDataSlotメソッドにより、データを格納する「データスロット」をすべてのスレッドに割り当てます。スロットにデータを格納するにはThread.SetDataメソッド、取得するにはThread.GetDataメソッドを使用します。

 サンプル「tls_01」に、AllocateDataSlotを使った例を示します。

「VB.NET/tls_01/Class1.vb」 (VB.NET)
Class Class1
    Private Shared slot As LocalDataStoreSlot

    'エントリポイント
    Shared Sub Main()
        'すべてのスレッドにデータスロットを割り当てる
        slot = System.Threading.Thread.AllocateDataSlot()

        'メインスレッドのスロットの内容を設定
        System.Threading.Thread.SetData(slot, "こんにちは")

        'Threadオブジェクトを作成する
        Dim t As New System.Threading.Thread( _
            New System.Threading.ThreadStart(AddressOf DoSomething))
        'スレッドを開始する
        t.Start()

        t.Join()

        'メインスレッドのスロットの内容を取得
        Dim str As String = _
            CStr(System.Threading.Thread.GetData(slot))
        Console.WriteLine(str)

        Console.ReadLine()
    End Sub

    Private Shared Sub DoSomething()
        '別スレッドのスロットの内容を設定
        System.Threading.Thread.SetData(slot, "さようなら")

        '別スレッドのスロットの内容を取得
        Dim str As String = _
            CStr(System.Threading.Thread.GetData(slot))
        Console.WriteLine(str)
    End Sub
End Class
「C#/tls_01/Class1.cs」 (C#)
class Class1
{
    private static LocalDataStoreSlot slot;

    //エントリポイント
    static void Main()
    {
        //すべてのスレッドにデータスロットを割り当てる
        slot = System.Threading.Thread.AllocateDataSlot();

        //メインスレッドのスロットの内容を設定
        System.Threading.Thread.SetData(slot, "こんにちは");

        //Threadオブジェクトを作成する
        System.Threading.Thread t = 
            new System.Threading.Thread(
            new System.Threading.ThreadStart(DoSomething));
        //スレッドを開始する
        t.Start();

        t.Join();

        //メインスレッドのスロットの内容を取得
        string str = (string) System.Threading.Thread.GetData(slot);
        Console.WriteLine(str);

        Console.ReadLine();
    }

    private static void DoSomething()
    {
        //別スレッドのスロットの内容を設定
        System.Threading.Thread.SetData(slot, "さようなら");

        //別スレッドのスロットの内容を取得
        string str = (string) System.Threading.Thread.GetData(slot);
        Console.WriteLine(str);
    }
}

 このアプリケーションを実行すると、

さようなら
こんにちは

 と表示されます。

 まずメインスレッドでデータスロットに文字列「こんにちは」と格納し、その後に別スレッドでデータスロットに「さようなら」と格納しています。それぞれのデータがスレッド別に格納されていることが分かります。

ThreadStaticAttribute

 スレッドローカルストレージをより簡単に使用する方法は、ThreadStaticAttribute属性を使うことです。静的フィールドにThreadStaticAttribute属性をつけることにより、このフィールドはスレッドごとに別の値を設定、取得できるようになります。

 ThreadStaticAttributeを使用した例を、サンプル「tls_02」に示します。

「VB.NET/tls_02/Class1.vb」 (VB.NET)
Class Class1
    'スレッドごとに一意な静的フィールド
    <ThreadStatic()> _
    Private Shared slotData As String

    'エントリポイント
    Shared Sub Main()
        'メインスレッドのslotDataの内容を設定
        slotData = "こんにちは"

        'Threadオブジェクトを作成する
        Dim t As New System.Threading.Thread( _
            New System.Threading.ThreadStart(AddressOf DoSomething))
        'スレッドを開始する
        t.Start()

        t.Join()

        'メインスレッドのslotDataの内容を取得
        Console.WriteLine(slotData)

        Console.ReadLine()
    End Sub

    Private Shared Sub DoSomething()
        '別スレッドのslotDataの内容を設定
        slotData = "さようなら"

        '別スレッドのslotDataの内容を取得
        Console.WriteLine(slotData)
    End Sub
End Class
「C#/tls_02/Class1.cs」 (C#)
class Class1
{
    //スレッドごとに一意な静的フィールド
    [ThreadStatic]
    private static string slotData;

    //エントリポイント
    static void Main()
    {
        //メインスレッドのslotDataの内容を設定
        slotData = "こんにちは";

        //Threadオブジェクトを作成する
        System.Threading.Thread t = 
            new System.Threading.Thread(
            new System.Threading.ThreadStart(DoSomething));
        //スレッドを開始する
        t.Start();

        t.Join();

        //メインスレッドのslotDataの内容を取得
        Console.WriteLine(slotData);

        Console.ReadLine();
    }

    private static void DoSomething()
    {
        //別スレッドのslotDataの内容を設定
        slotData = "さようなら";

        //別スレッドのslotDataの内容を取得
        Console.WriteLine(slotData);
    }
}

 このアプリケーションを実行すると先と同じく、

さようなら
こんにちは

 と表示されます。

 別スレッドでslotDataの値を「さようなら」としていますが、メインスレッドでslotDataを取得すると「こんにちは」のままとなっていることに注目してください。

シングルトンとダブルチェックロッキング

 これらの問題はここで取り上げるべきものではないかもしれませんが、興味深い話題であるため、ごく簡単に触れておきます。

 シングルトン(Singleton)デザインパターンとは、あるクラスのインスタンスがただ1つであることが保障され、そのインスタンスにグローバルなアクセスを設定するデザインパターンです。

 .NET Frameworkでスレッドセーフなシングルトンを実装する方法は、MSDNライブラリの「C# でのシングルトンの実装」や「Exploring the Singleton Design Pattern」、「Implementing the Singleton Pattern in C#」が参考になります。つまり基本的には、

  • 静的な初期化を行うか
  • ダブルチェックロッキング(Double-Check Locking)を使うか
  • ダブルチェックロッキングを使わずに同期を行うか

 ということになります。結論を言いますと、.NETでは、静的な初期化を行う方法がベストです。

 また、「volatile and MemoryBarrier()...」などでは、ダブルチェックロッキングでvolatileの代わりにThread.MemoryBarrierメソッドを使った方法が紹介されています。

最後に

 今後、より高いレベルの勉強をしたいという方には、下の参考資料がお勧めです。中でも、参考資料1はかなりお勧めです。この記事を参考にしていることを明記している記事は見かけませんが、明らかにそうであると思われる日本語の記事はよく見ます。また、公開されているライブラリにも便利なクラスがあります。

 この記事が読者の皆様のお役に立つことを祈っております。

参考資料

  1. Jon's Homepage! 『Multi-threading in .NET』
  2. MSDNライブラリ 『.NET Framework開発者ガイド-スレッド処理』
  3. MSDNライブラリ 『Visual Basic言語の概念-Visual Basic .NETにおけるマルチスレッド』
  4. MSDNライブラリ 『.NET Framework開発者ガイド-非同期呼び出しの組み込み』
  5. MSDNライブラリ 『コンポーネントのマルチスレッド』
  6. MSDNライブラリ 『スレッド処理のデザイン ガイドライン』
  7. MSDNライブラリ 『非同期プログラミングのガイドライン』
  8. MSDNライブラリ 『Chapter 4 - Architecture and Design Review of a .NET Application for Performance and Scalability』

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
.NET Frameworkにおけるマルチスレッドプログラミングの基本連載記事一覧

もっと読む

この記事の著者

どぼん!(ドボン!)

DOBON.NET内で.NET Frameworkの機能を紹介したWebサイト.NET Tipsやメールマガジン「.NETプログラミング研究」の発行人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/141 2006/07/11 14:37

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー