sma*_*man 83 .net c# multithreading locking monitor
何时在C#中使用Monitor类或lock关键字来确保线程安全?
编辑:
到目前为止,答案似乎lock是对Monitor课程的一系列调用的简写.锁定电话到底是什么?或者更明确地说,
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 ?
}
}
Run Code Online (Sandbox Code Playgroud)
更新
谢谢大家的帮助:我发布了另一个问题,作为您提供的一些信息的后续跟进.由于您似乎精通这一领域,我发布了链接:此锁定和管理锁定异常的解决方案有什么问题?
Cod*_*aos 87
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);
}
Run Code Online (Sandbox Code Playgroud)
它取决于Monitor.Enter锁定时原子设置标志.
早些时候它是:
var temp = obj;
Monitor.Enter(temp);
try
{
body
}
finally
{
Monitor.Exit(temp);
}
Run Code Online (Sandbox Code Playgroud)
这依赖于也不例外之间被抛出Monitor.Enter和try.我认为在调试代码中这种情况被违反了,因为编译器在它们之间插入了一个NOP,从而在那些可能之间进行了线程中断.
Luk*_*tný 41
lock只是Monitor.Enter带try+ finally和的快捷方式Monitor.Exit.只要它足够就使用lock语句 - 如果你需要像TryEnter这样的东西,你将不得不使用Monitor.
She*_*Pro 20
锁定语句相当于:
Monitor.Enter(object);
try
{
// Your code here...
}
finally
{
Monitor.Exit(object);
}
Run Code Online (Sandbox Code Playgroud)
但是,请记住Monitor也可以使用Wait()和Pulse(),这在复杂的多线程情况下通常很有用.
更新
但是在C#4中它的实现方式不同:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
//your code
}
finally
{
if (lockWasTaken)
Monitor.Exit(temp);
}
Run Code Online (Sandbox Code Playgroud)
Thanx到CodeInChaos的评论和链接
Monitor更灵活.对我来说,最喜欢使用显示器的情况是当你不想等到轮到你时,只需跳过:
//already executing? forget it, lets move on
if(Monitor.TryEnter(_lockObject))
{
//do stuff;
Monitor.Exit(_lockObject);
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所说,lock"等同于"
Monitor.Enter(object);
try
{
// Your code here...
}
finally
{
Monitor.Exit(object);
}
Run Code Online (Sandbox Code Playgroud)
但出于好奇,lock将保留您传递给它的第一个引用,如果您更改它将不会抛出.我知道不建议更改锁定的对象而你不想这样做.
但同样,对于科学来说,这很好:
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());
Run Code Online (Sandbox Code Playgroud)
......而这不是:
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());
Run Code Online (Sandbox Code Playgroud)
错误:
70783sTUDIES.exe中出现类型'System.Threading.SynchronizationLockException'的异常,但未在用户代码中处理
附加信息:从非同步代码块调用对象同步方法.
这是因为因为是不可变的,所以Monitor.Exit(lockObject);行为lockObject已经改变了strings,然后你从一个不同步的代码块中调用它..但无论如何.这只是一个有趣的事实.