4

我有一个在 C++ 中很容易解决的问题,但在 C# 中我仍然找不到一个好的解决方案:

我有一个函数 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 回答
2

您不需要锁定这些对象。您锁定执行逻辑的代码:

  static object lockObject = new object();
  static void foo(object o1, object o2)
  {
     lock (lockObject)
     {
        // this code will be executed on one thread at the time. Why lock o1 & o2??
     }
  }
于 2013-07-08T19:12:35.990 回答