C# チュートリアルlogin
C# チュートリアル
著者:php.cn  更新時間:2022-04-11 14:06:23

C# マルチスレッド



Threadはプログラムの実行パスとして定義されます。各スレッドは固有の制御フローを定義します。アプリケーションに複雑で時間のかかる操作が含まれる場合、各スレッドが特定の作業を実行するように、異なるスレッド実行パスを設定することが有益なことがよくあります。

スレッドは軽量プロセスです。スレッドの一般的な使用例は、最新のオペレーティング システムでの並列プログラミングの実装です。スレッドを使用すると、無駄な CPU サイクルが節約され、アプリケーションの効率が向上します。

これまでに作成したプログラムは、アプリケーションの実行インスタンスの単一プロセスとして実行される単一のスレッドです。ただし、このサブアプリケーションは一度に 1 つのタスクしか実行できません。複数のタスクを同時に実行するために、より小さなスレッドに分割できます。

スレッド ライフ サイクル

スレッド ライフ サイクルは、System.Threading.Thread クラスのオブジェクトが作成されたときに開始され、スレッドが終了するか実行が完了したときに終了します。

スレッド ライフ サイクルのさまざまな状態を以下に示します。

  • 未開始状態: スレッド インスタンスが作成されたが、Start メソッドが呼び出されない状況。

  • 準備完了状態: スレッドが実行準備ができており、CPU サイクルを待機している状態。

  • 実行不能状態: 次の状況ではスレッドは実行できません:


    • Sleepメソッドが呼び出された

    • Waitメソッドが呼び出された

    • 私を通して/ O 操作のブロック

  • 停止状態: スレッドが実行を完了したか、中止されたときの状態。

メインスレッド

C# では、System.Threading.Thread クラスがスレッドの作業に使用されます。これにより、マルチスレッド アプリケーションで個々のスレッドの作成とアクセスが可能になります。プロセス内で最初に実行されるスレッドは、メインスレッドと呼ばれます。

C# プログラムの実行が開始されると、メインスレッドが自動的に作成されます。 Thread クラスを使用して作成されたスレッドは、メインスレッドの子スレッドによって呼び出されます。 Thread クラスの CurrentThread プロパティを使用してスレッドにアクセスできます。

次のプログラムは、メイン スレッドの実行を示します:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class MainThreadProgram
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
            th.Name = "MainThread";
            Console.WriteLine("This is {0}", th.Name);
            Console.ReadKey();
        }
    }
}

上記のコードがコンパイルされて実行されると、次の結果が生成されます:

This is MainThread

Thread クラスの一般的に使用されるプロパティとメソッド

次の表は、 スレッド クラスのいくつかの一般的に使用される 属性 :

PropertyDescription
CurrentContext スレッドが実行されている現在のコンテキストを取得します。
CurrentCulture 現在のスレッドのカルチャを取得または設定します。
CurrentPrinciple スレッドの現在のプリンシパルを取得または設定します (ロールベースのセキュリティの場合)。
CurrentThread現在実行中のスレッドを取得します。
CurrentUICulture 実行時にカルチャ固有のリソースを検索するためにリソース マネージャーによって使用される現在のカルチャを取得または設定します。
ExecutionContext 現在のスレッドのさまざまなコンテキストに関する情報を含む ExecutionContext オブジェクトを取得します。
IsAlive 現在のスレッドの実行ステータスを示す値を取得します。
IsBackgroundスレッドがバックグラウンド スレッドであるかどうかを示す値を取得または設定します。
IsThreadPoolThreadスレッドがマネージド スレッド プールに属しているかどうかを示す値を取得します。
ManagedThreadId 現在のマネージド スレッドの一意の識別子を取得します。
Name スレッドの名前を取得または設定します。
Priorityスレッドのスケジューリング優先度を示す値を取得または設定します。
ThreadState 現在のスレッドの状態を含む値を取得します。

次の表は、Thread クラスの一般的に使用されるいくつかの メソッド を示しています。

シリアル番号メソッド名と説明
1public void Abort()
このメソッドを呼び出しているスレッドで ThreadAbortException をスローし、このスレッドを終了するプロセスを開始します。通常、このメソッドを呼び出すとスレッドが終了します。
2public static LocalDataStoreSlot AllocateDataSlot()
すべてのスレッドに名前のないデータ スロットを割り当てます。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
3public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
すべてのスレッドに名前付きデータ スロットを割り当てます。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
4public static void BeginCriticalRegion()
スレッドの中断や未処理の例外の影響により、アプリケーション ドメイン内の他のタスクに悪影響を及ぼす可能性があるコード領域に実行が進入しようとしていることをホストに通知します。
5public static void BeginThreadAffinity()
現在の物理オペレーティング システム スレッドの ID に依存する命令が実行されようとしていることをホスト管理コードに通知します。
6public static void EndCriticalRegion()
スレッドが中止されるか未処理の例外が現在のタスクにのみ影響を及ぼすコード領域に実行が進入しようとしていることをホストに通知します。
7public static void EndThreadAffinity()
現在の物理オペレーティング システム スレッドの ID に依存する命令の実行が終了したことをホスト管理コードに通知します。
8public static void FreeNamedDataSlot(string name)
プロセス内のすべてのスレッドの名前とスロットの関連付けを削除します。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
9public static Object GetData( LocalDataStoreSlot スロット )
現在のスレッドの現在のドメインにある現在のスレッドの指定されたスロットから値を取得します。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
10public static AppDomain GetDomain()
現在のスレッドが実行されている現在のドメインを返します。
11public static AppDomain GetDomainID()
一意のアプリケーション ドメイン識別子を返します。
12public static LocalDataStoreSlot GetNamedDataSlot( 文字列名 )
名前付きデータ スロットを見つけます。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
13public void Interrupt()
WaitSleepJoin スレッド状態のスレッドを中断します。
14public void Join()
標準の COM および SendMessage メッセージ ポンプの処理が継続している間、いずれかのスレッドが終了するまで呼び出し元のスレッドをブロックします。このメソッドにはさまざまなオーバーロードがあります。
15public static void MemoryBarrier()
メモリアクセスを次のように同期します: 現在のスレッドを実行しているプロセッサが命令を並べ替えるとき、最初に MemoryBarrier を呼び出した後はメモリアクセスを使用できません。 MemoryBarrier 呼び出しを実行します。
16public static void ResetAbort()
現在のスレッドに対して要求された中止をキャンセルします。
17public static void SetData( LocalDataStoreSlot スロット、 オブジェクトデータ )
現在実行中のスレッド上のこのスレッドの現在のドメインの指定されたスロットにデータを設定します。パフォーマンスを向上させるには、代わりに ThreadStaticAttribute 属性でマークされたフィールドを使用してください。
18public void Start()
スレッドを開始します。
19public static void Sleep( int ミリ秒タイムアウト )
スレッドをしばらく一時停止させてください。
20public static void SpinWait( 整数の反復 )
iterations パラメーターで定義された時間だけスレッドを待機させます。
21public static byte VolatileRead( 参照バイトアドレス )
public static double VolatileRead( 参照ダブルアドレス )
public static int VolatileRead( 参照整数アドレス )
public static Object VolatileRead( refオブジェクトアドレス )

フィールド値を読み取ります。この値は、プロセッサの数やプロセッサ キャッシュの状態に関係なく、コンピュータのプロセッサによって書き込まれた最新の値です。このメソッドにはさまざまなオーバーロードがあります。ここでは一部の形式のみを示します。
22public static void VolatileWrite( 参照バイトアドレス、 バイト値 )
public static void VolatileWrite( 参照ダブルアドレス、 二重値 )
public static void VolatileWrite( ref int アドレス、 int値 )
public static void VolatileWrite( ref オブジェクトアドレス、 オブジェクトの値 )

フィールドに値を即座に書き込み、その値がコンピューター内のすべてのプロセッサーに表示されるようにします。このメソッドにはさまざまなオーバーロードがあります。ここでは一部の形式のみを示します。
23public static bool Yield()
呼び出しスレッドに、現在のプロセッサ上で実行する準備ができている別のスレッドを実行させます。オペレーティング システムは、実行するスレッドを選択します。

スレッドの作成

スレッドは、Threadクラスを拡張することによって作成されます。拡張された Thread クラスは、Start() メソッドを呼び出して、子スレッドの実行を開始します。

次のプログラムは、この概念を示しています:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

上記のコードがコンパイルされて実行されると、次の結果が生成されます:

In Main: Creating the Child thread
Child thread starts

スレッドの管理

Thread クラスは、スレッドを管理するためのさまざまなメソッドを提供します。

次の例は、特定の時間にスレッドを一時停止するために使用される sleep() メソッドの使用方法を示しています。

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            // 线程暂停 5000 毫秒
            int sleepfor = 5000; 
            Console.WriteLine("Child Thread Paused for {0} seconds", 
                              sleepfor / 1000);
            Thread.Sleep(sleepfor);
            Console.WriteLine("Child thread resumes");
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

上記のコードをコンパイルして実行すると、次の結果が生成されます:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

スレッドを破棄します

Abort()メソッドを使用してスレッドを破棄します。

実行時に threadabortException をスローしてスレッドを中止します。この例外はキャッチできません。finally ブロックがある場合、制御は finally ブロックに送られます。

次のプログラムはこれを示しています:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {

                Console.WriteLine("Child thread starts");
                // 计数到 10
                for (int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Child Thread Completed");

            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally
            {
                Console.WriteLine("Couldn't catch the Thread Exception");
            }

        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            // 停止主线程一段时间
            Thread.Sleep(2000);
            // 现在中止子线程
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

上記のコードがコンパイルされて実行されると、次の結果が生成されます:

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception

PHP中国語ウェブサイト