4

C++ では簡単に解決できる質問がありますが、C# ではまだ適切な解決策が見つかりません。

2 つのオブジェクトをロックする必要がある関数 foo があり、この関数は逆の順序で引数を使用して呼び出すことができます。

    static void foo(object o1, object o2)
    {
        lock (o1)
        {
            lock (o2)
            {
                ...
            }
        }
    }

    static void bar(object a, object b)
    {
        ThreadPool.QueueUserWorkItem(s => foo(a, b));
        ThreadPool.QueueUserWorkItem(s => foo(b, a));
    }

これは、デッドロックを作成するための本による方法です。これを修正する標準的な方法は、オブジェクトを常に同じ順序でロックすることです。C++ ではポインターを比較することができましたが、「安全な」C# では非常に醜い解決策しかわかりませんMonitor.TryEntry(以下を参照)。もっと良いものはありますか?Equalsオブジェクトは変更可能であり、 、GetHashCode、 に依存できないことに注意してくださいIComparable

    static void foo(object o1, object o2)
    {
        const int Timeout = 1000;
        while (true)
        {
            if (Monitor.TryEnter(o1, Timeout))
            {
                try
                {
                    if (Monitor.TryEnter(o2, Timeout))
                    {
                        try
                        {
                            ...
                            return;
                        }
                        finally
                        {
                            Monitor.Exit(o2);
                        }
                    }
                }
                finally
                {
                    Monitor.Exit(o1);
                }
            }
        }
    }
4

2 に答える 2

3

同じ順序付きロック アプローチが必要な場合は、ロックに使用しているオブジェクトにいくつかのプロパティを追加し、それに基づいて比較できます。ケースで何が機能するかに応じて、クラスまたはインターフェイスを使用できます(つまりIComparable、オブジェクトのロックに実装します)。以下のサンプルでは、Less​​比較機能を持つクラスを使用しています。

class ComparableLockingObject
{
    static int LastOrderValue = 0;
    private orderValue = LastOrderValue++;

    public bool Less(ComparableLockingObject other)
    {
       return this.orderValue < other.orderValue;
    }
}

static void foo(ComparableLockingObject o1, ComparableLockingObject o2,
    Action action)
{
   if (o2.Less(o1))
   {
      var temp = o1;
      o1 = o2;
      o2 = temp;
   }

   lock (o1)
   {
        lock (o2)
        {
           action();
        }
    }
}
于 2013-07-08T19:39:37.700 に答える