在c#程序中,我有2个线程启动存储过程。 此存储过程在一些表中读取和写入数据。
当我启动程序时,我有时会遇到SQL服务器异常(锁定问题)。
为了避免死锁,我尝试在程序中添加lock(this){ ... }
以避免同时调用此存储过程但没有成功(相同的例外)
如何解决这个问题?
答案 0 :(得分:2)
lock(this)
将无法解决您的并发问题,因为锁将引用不同的this
引用,即
public class Locker
{
public void Work()
{
lock (this)
{
//do something
}
}
}
用作(假设这些代码并行运行)
Locker first = new Locker(); Locker second = new Locker();
first.Work() // <-- locks on first second.Work() // <-- locks on second
将锁定不同的对象,而不是真正锁定。
使用此模式
public class Locker
{
private static object lockObject = new object();
// a static doodad for locking
public void Work()
{
lock (lockObject)
{
//do something
}
}
}
在这两种情况下,都会锁定同一个东西,并使第二个呼叫等待。
但是,根据我的经验,在大多数情况下,SQL Server过程中的锁定问题是过程本身的错误,保持事务打开的时间比需要的长,打开不需要的事务,查询次优等等。使sp调用等待在C#代码中,而不是在SQL Server排队等待,并不能解决这些问题。
此外,死锁是一类特殊的问题,几乎总是可以通过重构解决方案来解决数据访问问题。向我们提供有关该问题的更多信息,可能存在根本不需要应用程序级锁定的解决方案。
答案 1 :(得分:0)
正如@SWeko解释的那样,C#的lock
只会解决当前AppDomain的线程之间的并发问题,所以如果有多个AppDomain正在运行,那么为了简单起见,让我们说两个桌面客户端,那么它们会遇到僵局。有关详细信息,请参阅Cross-Process Locking in C#和What is the difference between lock and Mutex?。
即使在桌面应用程序的情况下,处理存储过程中的死锁问题也会好得多。默认行为是您的第二个请求将等到第一个完成的超时,如果您不想等待,则使用WITH(NOWAIT)
。 Explore more