Csharp-multithreading
C#-マルチスレッド
- スレッド*は、プログラムの実行パスとして定義されます。 各スレッドは、制御の一意のフローを定義します。 アプリケーションに複雑で時間のかかる操作が含まれる場合、各スレッドが特定のジョブを実行するように、異なる実行パスまたはスレッドを設定すると役立つことがよくあります。
スレッドは*軽量プロセス*です。 スレッドの一般的な使用例の1つは、最新のオペレーティングシステムによる並行プログラミングの実装です。 スレッドを使用すると、CPUサイクルの無駄が節約され、アプリケーションの効率が向上します。
ここまでで、アプリケーションの実行インスタンスである単一プロセスとして単一スレッドが実行されるプログラムを作成しました。 ただし、この方法では、アプリケーションは一度に1つのジョブを実行できます。 一度に複数のタスクを実行するために、より小さなスレッドに分割できます。
スレッドのライフサイクル
スレッドのライフサイクルは、System.Threading.Threadクラスのオブジェクトが作成されると開始され、スレッドが終了または実行を完了すると終了します。
以下は、スレッドのライフサイクルにおけるさまざまな状態です-
- The Unstarted State -スレッドのインスタンスは作成されているが、Startメソッドが呼び出されていない状況です。
- 準備完了状態-スレッドの実行準備ができており、CPUサイクルを待機している状態です。
- 実行不可能な状態-スレッドが実行可能でない場合、
- Sleepメソッドが呼び出されました
- 待機メソッドが呼び出されました
- I/O操作によってブロックされました
- The Dead State -スレッドが実行を完了するか中止される状況です。
メインスレッド
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 クラスの properties を示しています-
Sr.No. | Property & Description |
---|---|
1 |
CurrentContext スレッドが実行されている現在のコンテキストを取得します。 |
2 |
CurrentCulture 現在のスレッドのカルチャを取得または設定します。 |
3 |
CurrentPrinciple スレッドの現在のプリンシパルを取得または設定します(ロールベースのセキュリティ用)。 |
4 |
CurrentThread 現在実行中のスレッドを取得します。 |
5 |
CurrentUICulture Resource Managerが実行時にカルチャ固有のリソースを検索するために使用する現在のカルチャを取得または設定します。 |
6 |
ExecutionContext 現在のスレッドのさまざまなコンテキストに関する情報を含むExecutionContextオブジェクトを取得します。 |
7 |
IsAlive 現在のスレッドの実行ステータスを示す値を取得します。 |
8 |
IsBackground スレッドがバックグラウンドスレッドであるかどうかを示す値を取得または設定します。 |
9 |
IsThreadPoolThread スレッドがマネージスレッドプールに属しているかどうかを示す値を取得します。 |
10 |
ManagedThreadId 現在のマネージスレッドの一意の識別子を取得します。 |
11 |
Name スレッドの名前を取得または設定します。 |
12 |
Priority スレッドのスケジューリング優先順位を示す値を取得または設定します。 |
13 |
ThreadState 現在のスレッドの状態を含む値を取得します。 |
次の表は、 Thread クラスで最も一般的に使用される methods の一部を示しています-
Sr.No. | Method & Description |
---|---|
1 |
public void Abort() 呼び出されたスレッドでThreadAbortExceptionを発生させて、スレッドを終了するプロセスを開始します。 このメソッドを呼び出すと、通常、スレッドが終了します。 |
2 |
public static LocalDataStoreSlot AllocateDataSlot() すべてのスレッドに名前のないデータスロットを割り当てます。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
3 |
public static LocalDataStoreSlot AllocateNamedDataSlot(string name) すべてのスレッドに名前付きデータスロットを割り当てます。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
4 |
public static void BeginCriticalRegion() スレッドの中止または未処理の例外の影響により、アプリケーションドメイン内の他のタスクが危険にさらされる可能性があるコードの領域に実行が入ろうとしていることをホストに通知します。 |
5 |
public static void BeginThreadAffinity() マネージコードが現在の物理オペレーティングシステムスレッドのIDに依存する命令を実行しようとしていることをホストに通知します。 |
6 |
public static void EndCriticalRegion() スレッドの中止または未処理の例外の影響が現在のタスクに制限されているコードの領域に実行が入ろうとしていることをホストに通知します。 |
7 |
public static void EndThreadAffinity() マネージコードが現在の物理オペレーティングシステムスレッドのIDに依存する命令の実行を終了したことをホストに通知します。 |
8 |
public static void FreeNamedDataSlot(string name) プロセス内のすべてのスレッドについて、名前とスロットの関連付けを削除します。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
9 |
public static Object GetData(LocalDataStoreSlot slot) 現在のスレッドの現在のドメイン内で、現在のスレッドの指定されたスロットから値を取得します。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
10 |
public static AppDomain GetDomain() 現在のスレッドが実行されている現在のドメインを返します。 |
11 |
public static AppDomain GetDomainID() 一意のアプリケーションドメイン識別子を返します |
12 |
public static LocalDataStoreSlot GetNamedDataSlot(string name) 名前付きデータスロットを検索します。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
13 |
public void Interrupt() WaitSleepJoinスレッド状態にあるスレッドを中断します。 |
14 |
public void Join() 標準のCOMおよびSendMessageのポンピングを実行しながら、スレッドが終了するまで呼び出し側のスレッドをブロックします。 このメソッドには、さまざまなオーバーロードフォームがあります。 |
15 |
public static void MemoryBarrier() メモリアクセスを次のように同期します。現在のスレッドを実行しているプロセッサは、MemoryBarrierの呼び出しに続くメモリアクセスの後にMemoryBarrierの呼び出し前のメモリアクセスが実行されるような方法で命令を並べ替えることはできません。 |
16 |
public static void ResetAbort() 現在のスレッドに対して要求された中止をキャンセルします。 |
17 |
public static void SetData(LocalDataStoreSlot slot, Object data) 現在実行中のスレッドの指定されたスロットに、そのスレッドの現在のドメインのデータを設定します。 パフォーマンスを向上させるには、代わりにThreadStaticAttribute属性でマークされたフィールドを使用します。 |
18 |
public void Start() スレッドを開始します。 |
19 |
public static void Sleep(int millisecondsTimeout) スレッドを一定時間一時停止します。 |
20 |
public static void SpinWait(int iterations) スレッドは、繰り返しパラメーターで定義された回数だけ待機します |
21 |
public static byte VolatileRead(ref byte address)
フィールドの値を読み取ります。 値は、プロセッサの数またはプロセッサキャッシュの状態に関係なく、コンピュータのプロセッサによって書き込まれた最新の値です。 このメソッドには、さまざまなオーバーロードフォームがあります。 上記の一部のみを示します。 |
22 |
値をすぐにフィールドに書き込み、その値がコンピューター内のすべてのプロセッサーから見えるようにします。 このメソッドには、さまざまなオーバーロードフォームがあります。 上記の一部のみを示します。 |
23 |
現在のプロセッサで実行する準備ができている別のスレッドに呼び出しスレッドを実行させます。 オペレーティングシステムは、譲るスレッドを選択します。 |
スレッドを作成する
スレッドは、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");
//the thread is paused for 5000 milliseconds
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_ブロック(存在する場合)に送信されます。
次のプログラムはこれを示しています-
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
try {
Console.WriteLine("Child thread starts");
//do some work, like counting to 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();
//stop the main thread for some time
Thread.Sleep(2000);
//now abort the child
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