监控与locking

什么时候在C#中使用Monitor类或lock关键字来保证线程安全?

编辑:从迄今为止的答案看来, lockMonitor类的一系列调用的简短手段。 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.Enterprimefaces地设置标志,当locking被采取。


早些时候是这样的:

 var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); } 

这依赖于Monitor.Entertry之间没有引发exception。 我觉得在debugging代码中,这个条件被违反了,因为编译器在它们之间插入了一个NOP,从而在可能的线程之间进行线程中断。

lock只是Monitor.Enter快捷键,用try + finallyMonitor.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); }