2

我需要在我们的框架中实现应该执行锁定机制的类。我们有几个线程,它们的编号为 0,1,2,3.... 我们有一个名为 的静态类ResourceHandler,它应该将这些线程锁定在给定的对象上。要求是 nLock()调用应由 mRelease()调用实现,其中 n = [0..] 和 m = [0..]。因此,无论对单个对象执行多少锁,只需一次Release() 调用就足以解锁所有对象。更进一步,如果 o 对象没有被锁定,Release()调用应该什么也不做。我们还需要知道哪些对象被锁定在哪些线程上。

我有这个实现:

public class ResourceHandler
{
    private readonly Dictionary<int, List<object>> _locks = new Dictionary<int, List<object>>();

    public static ResourceHandler Instance {/* Singleton */}

    public virtual void Lock(int threadNumber, object obj)
    {
        Monitor.Enter(obj);

        if (!_locks.ContainsKey(threadNumber)) {_locks.Add(new List<object>());}
        _locks[threadNumber].Add(obj);
    }

    public virtual void Release(int threadNumber, object obj)
    {
       // Check whether we have threadN in _lock and skip if not
       var count = _locks[threadNumber].Count(x => x == obj);
       _locks[threadNumber].RemoveAll(x => x == obj);

       for (int i=0; i<count; i++)
       {
           Monitor.Exit(obj);
       }
    }

    // .....
 }

实际上我在这里担心的是线程安全。我实际上不确定,它是否是线程安全的,修复它真的很痛苦。我是否正确地完成了任务,如何确保这是线程安全的?

4

4 回答 4

2

您的Lock方法锁定在目标objects 上,但_locks任何线程都可以随时访问字典。您可能想要添加一个私有锁对象来访问字典(在LockRelease方法中)。

还要记住,通过使用这样的 ResourceHandler,其余代码(消费线程)有责任释放所有使用的对象(lock ()例如,一个常规块涵盖了该问题,因为每当您离开lock的范围时,该对象发行了)。

您可能还想ReferenceEquals在计算对象被锁定的次数时使用,而不是==.

于 2012-07-04T09:13:30.887 回答
1

您可以通过使用ConcurrentDictionary来确保此类是线程安全的,但是它不会帮助您解决您在尝试开发自己的锁定机制时遇到的所有问题。

有许多锁定机制已经是 .Net Framework 的一部分,您应该使用它们。

听起来您将需要使用这些组合,包括等待句柄来实现您想要的。


编辑

仔细阅读后,我认为您可能需要一个EventWaitHandle

于 2012-07-04T09:12:39.210 回答
1

从概念上讲,您所拥有的东西看起来很危险;这是因为调用Monitor.EnterMonitor.Exit让它们作为Lock语句工作,建议将它们封装在一个try/finally块中,即确保它们按顺序执行。Monitor.Exit之前调用Monitor.Enter会抛出异常。

为了避免这些问题(如果抛出异常,给定线程的锁可能会或可能不会被占用,如果锁被占用,它将不会被释放,导致锁泄漏。我建议使用一个上面其他答案中提供的选项。但是,如果您确实想继续使用此机制,CLR 4.0 将以下重载添加到Monitor.Enter方法中

public static void Enter (object, ref bool lockTaken);

lockTaken当且仅当Enter方法抛出异常并且未获取锁时才为假。因此,使用使用全局的两种方法,bool lockTaken您可以创建类似的东西(这里的示例是针对单个储物柜的 - 您将需要一个List<bool>与您的线程相对应的字典 - 或者更好的事件 a Tuple)。所以在你的方法中Lock你会有类似的东西

bool lockTaken = false;
Monitor.Enter(locker, ref lockTaken);

在另一种方法Release

if (lockTaken)
    Monitor.Exit(locker);

我希望这有帮助。

编辑:我不认为我完全理解你的问题,但据我所知,我会使用Concurrent Collection。这些是完全安全的。签出IProducerConsumerCollection<T>ConcurrentBag<T>。这些应该通过框架处理的所有线程安全来促进您想要的(注意。线程安全集合并不意味着它执行的代码是线程安全的!)。但是,使用这样的集合可能比使用锁要慢得多。

于 2012-07-04T09:26:23.473 回答
0

IMO 你需要使用原子函数集来保证它的安全。

http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx

我想互斥锁会帮助你。

于 2012-07-04T09:03:49.190 回答