スレッド:スレッドは、プロセスの独立した実行単位です。他のスレッドを含めることができるメインスレッドを除いて、各プロセスにはメインスレッドがあります。
マルチスレッドの重要性:マルチスレッドは、プログラムの全体的な応答性を向上させ、CPUの効率を高めるのに役立ちます。
複数のスレッドが共有機能モジュールを同時に実行できるため、マルチスレッドアプリケーションドメインは非常に不安定です。アプリケーションのリソースが破壊されないように保護するために、マルチスレッドプログラムには、モニタークラス、ロックキーワード、ミューテックスクラスの3つのロックメカニズムが用意されています。
1.ロック
ロックによって実現される機能は次のとおりです。後で入るスレッドは現在のスレッドを中断しませんが、続行する前に現在のスレッドの終了を待ちます。
応用:
private Object thisLock=new object();
lock(thisLock){
//锁定的代码块
}
注:パブリックタイプをロックしないでください。ロックしないと、インスタンスがコードの制御を超えてしまいます。
一般的な構造lock(this)、lock(typeof(MyType))、およびlock( "myLock")は
、このガイドラインに違反しています。インスタンスがパブリックにアクセス可能である場合、lock(this)の問題が発生します。
MyTypeがパブリックにアクセス可能な場合、ロック(typeof(MyType))の問題が発生します。
同じ文字列を使用するプロセス内の他のコードは同じロックを共有するため、lock( "myLock")の問題が発生します。
ベストプラクティスは、ロックするプライベートオブジェクトを定義するか、すべてのインスタンスで共有されるデータを保護するプライベート静的オブジェクト変数を定義することです。
次の例は、ロックの適用を示しています。
次の例では、5つのセカンダリスレッドが作成され、セカンダリスレッドによって完了されるタスクは次のとおりです。スレッドコードを出力し、1秒遅延してから、その時点の時間を出力します。
例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication5 {
class Program {
static void Main(string[] args) {
Console.WriteLine ("程序开始时间:"+DateTime.Now .ToString());
Example ex=new Example ();
Thread []threads=new Thread[5];
for (int i=0;i<5;i++)
{
threads[i]=new Thread (new ThreadStart(ex.OutPut));
threads[i].Name =string.Format ("Worker thread#{0}",i) ;
}
foreach(Thread t in threads){
t.Start();
}
Console.WriteLine("主线程最后一句代码!"+DateTime.Now.ToString());
}
}
class Example{
private static object thisLock=new object ();
public void OutPut()
{
lock(thisLock){
Console .WriteLine("->{0}",Thread.CurrentThread.Name);
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now);
}
}
}
}
実験結果は以下のとおりです。
図1:ロックの追加
図2:ロックなし
実験結果から、ロックを追加した後、プログラムは一度に1つのスレッドしか実行できず、現在のスレッドが実行された場合にのみ、次のスレッドがロックなしで実行されることがわかります。プログラムの実行は無秩序でブロックしやすいです。
2.監視
ロックはモニターのEnterおよびExitのカプセル化であるため、MonitorクラスのEnter()メソッドとExit()メソッドの組み合わせをlockキーワードに置き換えることができます。
ロック機能に加えて、Monitorクラスには次の機能もあります。
TryEnter()は、長期的な死亡の問題を解決します。同時実行が頻繁に発生し、長期間続く場合、TryEnterを使用すると、デッドロックや長時間の待機を効果的に防ぐことができます。
Wait()はオブジェクトのロックを解除して、他のスレッドがオブジェクトをロックしてアクセスできるようにします。他のスレッドがオブジェクトにアクセスすると、呼び出し元のスレッドは待機します。パルス信号は、オブジェクトの状態の変化を待機中のスレッドに通知するために使用されます。
Pulse()、PulseAll()は、1つ以上の待機中のスレッドに信号を送信します。この信号は、ロックされたオブジェクトの状態が変更され、ロックの所有者がロックを解放する準備ができていることを待機中のスレッドに通知します。待機中のスレッドは、最終的にオブジェクトロックを受信できるように、オブジェクトの準備完了キューに配置されます。スレッドがロックを取得すると、オブジェクトの新しい状態をチェックして、目的の状態に到達したかどうかを確認できます。
注:Pulse、PulseAll、およびWaitメソッドは、同期されたコードブロック内から呼び出す必要があります。
3.ミューテックス(ミューテックス)
Mutexの優れた機能は、アプリケーションドメインの境界を越えてリソースへの排他的アクセスを実行できることです。つまり、異なるプロセスのスレッドを同期するために使用できます。この機能は、より多くのシステムリソースを犠牲にします。
MutexとイベントオブジェクトEventWaitHandlerはカーネルオブジェクトに属します。カーネルオブジェクトはスレッドの同期に使用されます。スレッドはユーザーモードとカーネルモードを切り替える必要があるため、一般的に効率は非常に低くなります。ただし、相互に排他的なオブジェクトと、カーネルオブジェクトなどのイベントオブジェクトを使用すると、同期は、複数のプロセスのスレッド間で実行できます。
ミューテックスミューテックスはバトンに似ています。バトンを受け取るスレッドは実行を開始できます。もちろん、バトンは一度に1つのスレッドにのみ属します(スレッドアフィニティ)。このスレッドがバトンを解放しない場合(Mutex.ReleaseMutex)、実行するためにバトンを必要とする他のすべてのものスレッドは興奮を見るのを待つことしかできません。