「ソフトウェア開発性能最適化シリーズ」のマルチスレッド(回転)


1、スレッド同期


スレッド同期はマルチスレッドプログラムを記述する上でまず問題を考慮する必要がある.C#は、Win 32の臨界領域、反発オブジェクト、およびイベントオブジェクトを別々にパッケージするためのMonitor、Mutex、AutoResetEvent、およびManualResetEventオブジェクトのいくつかの基礎となる同期メカニズムを提供する.C#にはlock文も用意されており、使いやすく、コンパイラが適切なMonitorを自動的に生成します.EnterとMonitor.Exit呼び出し.

a)、同期粒度


 
同期粒度は、メソッド全体であってもよいし、メソッド内のコードのセグメントであってもよい.メソッドにMethodImplOptionsを指定します.Synchronizedプロパティは、メソッド全体にタグを同期させます.例:
[MethodImpl(MethodImplOptions.Synchronized)] public static SerialManager GetInstance() {  if (instance == null ) { instance = new SerialManager(); }  return instance; }

通常、同期の範囲を小さくして、システムのパフォーマンスを向上させる必要があります.メソッド全体を同期として単純にマークするのは、メソッド内の各コードが同期によって保護される必要があると判断できない限り、良いアイデアではありません.

b)、同期ポリシー


ロックを使用して同期を行い、同期オブジェクトはType、this、または同期の目的で特別に構築されたメンバー変数を選択できます.TypeをロックしてTypeオブジェクトをロックすると、同じプロセスのすべてのAppDomainタイプのすべてのインスタンスに影響を及ぼすことを回避します.これは、深刻なパフォーマンスの問題だけでなく、予期せぬ動作を引き起こす可能性があります.これはとても悪い習慣です.staticメソッドのみを含むタイプであっても、このメンバー変数をロックオブジェクトとして追加的にstaticのメンバー変数を構築する必要があります.thisをロックしてthisをロックすることは、インスタンスのすべての方法に影響を与えないでください.オブジェクトobjには、メソッドのセグメントコードに同期保護を設定するlock(this)を使用するAメソッドとBメソッドの2つのメソッドがあると仮定します.現在,何らかの理由でBメソッドもlock(this)を用いて同期保護を設定し始め,全く異なる目的のために可能である.これにより,A法が妨害され,その挙動が予知できない可能性がある.したがって、良い習慣としてlock(this)の使用を避けることをお勧めします.同期の目的で特別に構成されたメンバー変数を使用することが推奨されます.方法はnew同期の目的でのみ使用されるobjectオブジェクトです.複数のメソッドが同期を必要とし、異なる目的がある場合は、いくつかの同期メンバー変数をそれぞれ確立できます.

c)、集合同期


C#は、SynchronizedパッケージとSyncRootプロパティの2つの便利な同期メカニズムを提供します.
 // Creates and initializes a new ArrayList  ArrayList myAL = new ArrayList(); myAL.Add( " The " ); myAL.Add( " quick " ); myAL.Add( " brown " ); myAL.Add( " fox " );  // Creates a synchronized wrapper around the ArrayList  ArrayList mySyncdAL = ArrayList.Synchronized(myAL); 

Synchronizedメソッドを呼び出すと、すべての操作がスレッドのセキュリティを保証する同じセットのオブジェクトが返されます.mySyncdAL[0]=mySyncdAL[0]+「test」という文を考えると、読み書きには2つのロックが必要です.一般的に、効率は高くありません.SyncRootプロパティを使用することをお勧めします.

2、NameDataSlotの代わりにThreadStaticを使用する


 
NameDataSlotのThreadへのアクセスGetDataとThread.SetDataメソッドには、2つのロックに関するスレッド同期が必要です.1つはLocalDataStoreです.SetDataメソッドはAppDomainの1段階にロックをかける必要があり、もう1つはThreadNativeである.GetDomainLocalStoreメソッドでは、Processの1レベルのロックが必要です.下位レベルのインフラストラクチャサービスでNameDataSlotが使用されている場合、システムに深刻な伸縮性の問題が発生します.この問題を回避する方法はThreadStatic変数を用いることである.例は次のとおりです.
public sealed class InvokeContext { [ThreadStatic]  private static InvokeContext current;  private Hashtable maps = new Hashtable(); } 

 

3、マルチスレッドプログラミング技術


Double Checkテクノロジーを使用したオブジェクトの作成
internal IDictionary KeyTable {  get {  if ( this ._keyTable == null ) {  lock ( base ._lock) {  if ( this ._keyTable == null ) {  this ._keyTable = new Hashtable(); } } }  return this ._keyTable; } } 

単一のオブジェクトの作成は、一般的なプログラミングです.通常、lock文の後にオブジェクトが直接作成されますが、これは安全ではありません.ロックがオブジェクトをロックする前に、最初のif文に複数のスレッドが入っている可能性があります.2番目のif文を追加しないと、単一のインスタンスオブジェクトが繰り返し作成され、古いインスタンスの代わりに新しいインスタンスが作成されます.単一のオブジェクトのデータが破壊されないか、または何らかの理由で存在する場合は、Double Checkテクノロジーを使用することを考慮する必要があります.