2016-11-29 7 views
5

割り当てのために、C#-Lockを使用するか、または自己実装されたTaS-Lockを使用するオプションが必要です。私がTaS-Locksについて読んだことは、1つのアトムステップを使用して値を読み書きすることです。このために、C#でInterlockedクラスを使用することが提案されました。C#で自分のTaS-Lockを実装するにはどうしたらいいですか?

は、これまでのところ、これは私が持っているものであるが、矛盾した答えになるようだ:

public interface Lock 
{ 
    void Lock(); 
    void Unlock(); 
} 

public class C_Sharp_Lock : Lock 
{ 
    readonly Object myLock = new object(); 

    public void Lock() 
    { 
     Monitor.Enter(myLock); 
    } 

    public void Unlock() 
    { 
     Monitor.Exit(myLock); 
    } 
} 

public class Tas_Lock : Lock 
{ 
    int L = 0; 

    public void Lock() 
    { 
     while (0 == Interlocked.Exchange(ref L, 1)) { }; 
    } 

    public void Unlock() 
    { 
     Interlocked.Exchange(ref L, 0); 
    } 
} 

誰も私が間違ってここにやっている知っていますか?

編集:私は次のようにそれを変更しました

:ケビンに対する応答として

public class Tas_Lock : Lock 
{ 
    int L = 0; 

    public void Lock() 
    { 
     while (0 == Interlocked.CompareExchange(ref L, 1, 0)) { }; 
    } 

    public void Unlock() 
    { 
     Interlocked.Exchange(ref L, 0); 
    } 
} 

は、しかし、これはまだ一貫性のない結果を返します。

編集#2:C#のロックに変更:

public class C_Sharp_Lock : Lock 
{ 
    readonly Object myLock = new object(); 
    bool lockTaken = false; 

    public void Lock() 
    { 
     Monitor.Enter(myLock, ref lockTaken); 
    } 

    public void Unlock() 
    { 
     if (lockTaken) 
      Monitor.Exit(myLock); 
    } 
} 
+0

Exchangeではなく、Lock()でCompareExchangeを使用する必要があります。ロックが既に取られている場合は値を変更しないでください –

+0

これはカレッジの課題ですか、あなたがやっているコースですか?私は不思議です:) – vtortola

+0

@vtortolaそれは大学の課題の一部です。 – Heijmaaans

答えて

5

あなたが道にInterlocked.CompareExchange作品を誤解しています。これは、以前に提供されている比較対象の値と等しい場合は、数値的にスワップします。を返し、前の値を返します。要するに

Interlocked.CompareExchange(ref L, 1, 0)意志:Lは、それは1にLを設定し、以前の値が返され、0に等しい場合、Lは0

  • に等しいかどうか

    • チェック(0)
    • Lが0でない(したがって、1に等しい)場合、それは前の値を返します(1)

    そこから、何をやるべきことまでループですInterlocked.CompareExchangeは0を返します(つまり、ロックが取得されたことを意味します)。

    public class Tas_Lock 
    { 
        int L = 0; 
    
        public void Lock() 
        { 
         while (0 != Interlocked.CompareExchange(ref L, 1, 0)) { } 
        } 
    
        public void Unlock() 
        { 
         Interlocked.Exchange(ref L, 0); 
        } 
    } 
    

    2つのことに注意する:

    • Interlocked.ExchangeUnlockに置き換えることができ、あなたのコードでは、固定されたコードが

      Interlocked.CompareExchangeしばらく戻っ0を待っていますより速いVolatile.Write(またはさらに、議論はするが、簡単な書込み)

    • 割り当てがない場合は、 -in class SpinLock、これはすでにすべてのものを最適化しています。
  • +0

    説明をありがとう!これで修正されました。どのように使用したらよいか分かりました。 – Heijmaaans

    +0

    私は別の質問があります。標準のC#ロックを実装すると、ロックが取られなかったときにmonitor.Exitが終了しようとするため、時々例外が返されます。これを修正するために、boolを追加して、Monitor.Enterメソッドのオーバーロードを使用してロックを取得するかどうかを確認しました。このメソッドは、取得時にboolをtrueに設定します。しかし、パラメータをfalseに初期化する必要があることを示す引数の例外が発生するようになりました。私は私の変更を見ることができるように自分の投稿を編集しました。 – Heijmaaans

    +0

    @Heijmaaans Unlockの最後にlockTakenをfalseに戻していることを確認してください –

    関連する問題