Sil*_*ent 20 c# synchronization exception-handling
使用带有try块的锁有什么问题吗?我记得在某个地方读过我们应该总是尝试在try块中放入最少量的代码并在内部锁定自己使用try-finally块,你们在这里看到了什么错误.我需要处理那个锁中的代码这一事实块可以抛出异常
try
{
lock(syncblk)
{
// do some processing
}
}
catch(Exception e)
{
// do something with exception
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 41
我需要处理锁定块中的代码可能抛出异常的事实
这是你的问题.这是一个可怕的情况.
你为什么要先锁定?通常你锁定某些东西的原因是你想要实现以下逻辑:
如果你这样做,那么没有一个人能够看到锁着的门就能看到这个烂摊子.
例如,您可能希望以线程安全的方式交换变量"left"和"right"的值,因此您:
现在假设在发生混乱之后抛出异常.怎么了?我们直接跳到解锁,留下另一个线程看到的混乱.
这就是为什么你不应该在锁中抛出异常的原因; 它彻底击败了锁定的目的!锁的整个要点是确保除了负责清理混乱的线程之外,所有线程始终观察到状态是一致的.
如果你有一个可以从锁中抛出的异常,最好的办法就是摆脱那种可怕的情况.如果你不能这样做,那么确保你可以(1)一旦异常逃脱锁定就完全破坏进程,这样你所造成的混乱不会导致数据丢失或其他伤害 - 做一个FailFast和从轨道上对这个过程进行核对,这是确定的唯一方法 - 或者(2)编写回滚代码,撤销在退出锁之前你正在尝试的任何操作; 也就是说,把乱七八糟的东西收回原来的状态.
如果后者是你的策略,那么不要把try块放在锁外 ; 它在那里是无用的,因为即时控件通过异常离开锁定,另一个线程可能会崩溃和死亡,因为你暴露在它的混乱.将处理异常的try 放在锁中:
lock(whatever)
{
try
{
MakeAMess();
}
finally
{
CleanItUp();
// Either by completing the operation or rolling it back
// to the pre-mess state
}
}
Run Code Online (Sandbox Code Playgroud)
如果你有很强的可靠性要求,那么处理可能引发异常的锁定关键部分是一项极其困难的编程任务,最好留给专家; 如果您发现自己处于这种情况下,可以考虑使用受约束的执行区域.