2011-04-06 43 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