监控与locking
什么时候在C#中使用Monitor
类或lock
关键字来保证线程安全?
编辑:从迄今为止的答案看来, lock
是Monitor
类的一系列调用的简短手段。 locking电话究竟是什么? 或者更明确地说,
class LockVsMonitor { private readonly object LockObject = new object(); public void DoThreadSafeSomethingWithLock(Action action) { lock (LockObject) { action.Invoke(); } } public void DoThreadSafeSomethingWithMonitor(Action action) { // What goes here ? } }
更新
谢谢大家的帮助:我已经发布了另一个问题,作为你们提供的一些信息的后续。 由于您似乎熟悉了这方面的知识,所以我发布了这个链接: 这个解决scheme有什么问题来locking和pipe理locking的exception?
Eric Lippert在他的博客中谈到这一点: 锁和例外不混合
C#4.0和更早版本的等效代码不同。
在C#4.0中是这样的:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); { body } } finally { if (lockWasTaken) Monitor.Exit(temp); }
它取决于Monitor.Enter
primefaces地设置标志,当locking被采取。
早些时候是这样的:
var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); }
这依赖于Monitor.Enter
和try
之间没有引发exception。 我觉得在debugging代码中,这个条件被违反了,因为编译器在它们之间插入了一个NOP,从而在可能的线程之间进行线程中断。
lock
只是Monitor.Enter
快捷键,用try
+ finally
和Monitor.Exit
。 在足够的时候使用lock语句 – 如果你需要像TryEnter这样的东西,你将不得不使用Monitor。
locking语句相当于:
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
但是,请记住,Monitor也可以使用Wait()和Pulse() ,这在复杂的multithreading情况下通常很有用。
更新
但是在C#4中,其实现方式不同:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }
感谢CodeInChaos的注释和链接
两者都是一样的东西。 锁是c sharp关键字并使用Monitor类。
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
显示器的locking和基本行为(input+退出)大致相同,但是显示器有更多的选项可以让你更多地同步。
锁是一个快捷方式,它是基本用法的选项。
如果你需要更多的控制,显示器是更好的select。 您可以将Wait,TryEnter和Pulse用于高级用法(如障碍,信号量等)。
正如其他人所说, lock
是“相当于”
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
但是出于好奇, lock
将保留你传递给它的第一个引用,如果你改变它,它不会抛出。 我知道不build议更改locking的对象 ,你不想这样做。
但是,对于科学来说,这个工作正常:
var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); lock (lockObject) { lockObject += "x"; } })); Task.WaitAll(tasks.ToArray());
…而这不是:
var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); Monitor.Enter(lockObject); try { lockObject += "x"; } finally { Monitor.Exit(lockObject); } })); Task.WaitAll(tasks.ToArray());
错误:
在70783sTUDIES.exe中发生types“System.Threading.SynchronizationLockException”的exception,但未在用户代码中处理
附加信息:对象同步方法是从一个非同步的代码块调用的。
这是因为Monitor.Exit(lockObject);
将作用于lockObject
已经改变,因为strings
是不可变的,那么你从一个非同步的代码块调用它..但无论如何。 这只是一个有趣的事实。
Monitor
更灵活。 对我来说,最喜欢使用显示器的情况是, 当你不想等待轮到你时,跳过 :
//already executing? eff it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }