多重锁定任务(线程)

时间:2012-07-04 08:53:42

标签: c# multithreading thread-safety

我需要在我们的框架中实现应该执行锁定机制的类。 我们有几个线程,编号为0,1,2,3 ....我们有一个名为ResourceHandler的静态类,它应该锁定给定对象上的这些线程。要求是m Lock()调用应该重新发出n Release()个调用,其中n = [0 ..]和m = [0 ..]。因此,无论在单个对象上执行了多少次锁定,只有一次Release()调用足以解锁所有锁定。更进一步,如果没有锁定对象,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 个答案:

答案 0 :(得分:2)

您的Lock方法会锁定目标object,但任何线程都可以随时访问_locks字典。您可能希望添加用于访问字典的私有锁对象(在LockRelease方法中)。

还要记住,通过使用这样的ResourceHandler,其余代码(消费线程)有责任释放所有使用过的对象(例如,常规lock ()块可以解决这个问题,因为无论何时你离开lock的范围,对象被释放。

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

答案 1 :(得分:1)

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

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

听起来你需要使用这些的组合,包括Wait Handles来实现你想要的。


修改

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

答案 2 :(得分:1)

你在概念上看起来很危险;这是bacause调用Monitor.EnterMonitor.Exit为他们的Lock语句工作,是reccomended在try/finally块被封装,这是为了保证它们执行sequetally。 <{1}}之前调用Monitor.Exit会抛出异常。

为了避免这些问题(如果抛出异常,可能或者可能不会对给定线程进行锁定,如果采取锁定,则不会释放,导致泄漏锁定。我会使用上面其他答案中提供的选项之一进行推荐。但是,如果您确实想要使用此机制,CLR 4.0会向Monitor.Enter方法添加以下重载

Monitor.Enter
当且仅当public static void Enter (object, ref bool lockTaken); 方法抛出异常并且未执行锁定时,

lockTaken才为false。因此,使用全局Enter bool的两种方法,您可以创建类似的东西(这里的示例适用于单个储物柜 - 您需要一个与您的主题相对应的lockTaken字典 - 或事件更好a List<bool>)。因此,在您的方法Tuple中,您将拥有类似

的内容
Lock

在另一种方法bool lockTaken = false; Monitor.Enter(locker, ref lockTaken);

Release

我希望这会有所帮助。

编辑:我不认为我完全理解你的问题,但从我可以收集到的内容中我会使用Concurrent Collection。这些都是安全的。查看if (lockTaken) Monitor.Exit(locker); IProducerConsumerCollection<T>。这些应该促进你想要的所有线程由框架处理(注意:线程安全集合并不意味着它执行的代码是线程安全的!)。但是,使用这样的集合可能比使用锁定慢得多。

答案 3 :(得分:0)

IMO您需要使用原子功能集来确保其安全。

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

Mutexes我想会帮助你。