我需要在我们的框架中实现应该执行锁定机制的类。
我们有几个线程,编号为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);
}
}
// .....
}
实际上我在这里担心的是线程安全。我实际上不确定,它是否是线程安全的,修复它真的很痛苦。我是否正确地完成了任务,如何确保这是线程安全的?
答案 0 :(得分:2)
您的Lock
方法会锁定目标object
,但任何线程都可以随时访问_locks
字典。您可能希望添加用于访问字典的私有锁对象(在Lock
和Release
方法中)。
还要记住,通过使用这样的ResourceHandler,其余代码(消费线程)有责任释放所有使用过的对象(例如,常规lock ()
块可以解决这个问题,因为无论何时你离开lock
的范围,对象被释放。
在计算对象被锁定的次数而不是ReferenceEquals
时,您可能还想使用==
。
答案 1 :(得分:1)
您可以使用ConcurrentDictionary确保此类是线程安全的,但是,它无法帮助您解决尝试开发自己的锁定机制时遇到的所有问题。
有一些锁定机制已经是.Net Framework的一部分,你应该使用它们。
听起来你需要使用这些的组合,包括Wait Handles来实现你想要的。
修改强>
仔细阅读后,我认为您可能需要EventWaitHandle
答案 2 :(得分:1)
你在概念上看起来很危险;这是bacause调用Monitor.Enter
和Monitor.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我想会帮助你。