2011-04-06 39 views
0

在一个c#程序中,我有两个线程启动一个存储过程。 该存储过程在某些表中读取和写入数据。多线程程序中的Sql服务器锁异常

当我开始我的计划,我有时SQL服务器异常(锁定麻烦)。

为了避免死锁,我想在我的程序,以避免此存储过程的成功(同一除外),但没有同时呼叫

如何修复添加lock(this){ ... }

+4

如果你能证明在SP代码这将是一个更容易弄清楚为什么你得到一个僵局。 – 2011-04-06 13:13:05

回答

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程序锁定问题是程序本身的故障,持有交易比neccessary开放的时间越长,开不必要的交易,有次优查询等让您的SP调用在C#代码中排队等待,而不是在SQL Server中排队,并不能解决这些问题。

另外,死锁是并发性问题的一个特定的类别,几乎总是可以通过重构时考虑到数据访问的解决方案来解决。给我们提供关于这个问题的更多信息,可能有一个解决方案根本不需要应用程序级锁。

+1

你是对的,但我不会在我的应用程序代码中使用锁来防止数据库发生死锁,因为它太钝了。 SP可能需要调整。 – Polyfun 2011-04-06 13:20:05

+1

@ShellShock我同意,并且我添加了一个关于这个的澄清,但不正确地使用'lock'语句也很重要,因为这往往会产生“*看起来正确”的代码。 – SWeko 2011-04-06 13:23:28

0

正如@SWeko所解释的那样,C#的lock只能解决当前AppDomain的线程之间的并发问题,所以如果有多个AppDomain在运行,为了简单起见我们说两个桌面客户端,然后它们将会陷入死锁。有关更多详细信息,请参阅Cross-Process Locking in C#What is the difference between lock and Mutex?

它会好得多,即使在桌面应用程序的情况下,你处理死锁问题您的存储过程中。默认行为是您的第二个请求会等到第一个完成的超时,如果您不想等待,请使用WITH(NOWAIT)Explore more