2

我正在爲我的服務和SQL數據庫之間的多線程服務構建一個稍微高效的連接池。基本上歸結,我有了這個代碼在我的課:.NET多線程Synclock vs Monitor

Public Class DBMC 
Private Connections As New ArrayList 

    Private Function GetConnection() As Object 
    Dim conCounter As Integer = 0 

    While True 
     If Connections.Count > conCounter Then 
      If System.Threading.Monitor.TryEnter(Connections(conCounter), 10) Then 
       Return Connections(conCounter) 
      Else 
       conCounter += 1 
      End If 

     ElseIf conCounter > 98 Then 
      'keep looping until an open connection is found 
      conCounter = 0 

     ElseIf conCounter < 98 Then 
      Dim connection As Object = NewCon() 

      If connection Is Nothing Then 
       conCounter = 0 
      Else 
       Connections.Add(connection) 

       Return connection 
      End If 
     End If 
    End While 
    'below line should never run 
    Return Nothing 
    End Function 

    Public Function DBSelect(ByVal SQL As String) As DataSet 
    Dim connection As Object = GetConnection() 

    SyncLock (connection) 
     'Run the select vs database and do a bunch of other stuff 
    End SyncLock 

    Try 
     System.Threading.Monitor.Exit(connection) 
    Catch ex As Exception 
    End Try 

    Return DataSet 
    End Function 
End Class 

所以這個代碼工作絕對偉大,我能以最快的速度爲計算機可以使他們和它會打開8運行在不同的線程500個select語句不同的連接(可能是由於我的電腦速度,較慢的電腦可能打開更多)。問題是,在DBSelect函數中,我在Try/Catch中放置了一行以釋放顯示器Enter,因爲有時結束synclock將會丟棄對象上的鎖(在這種情況下,不需要該行並引發異常),有時該對象仍處於鎖定狀態,並且會保持永久鎖定狀態而不運行該行(在這種情況下,該對象將使用該對象併成功傳遞)。我無法弄清楚爲什麼有時它會釋放它,有時它不會。有任何想法嗎?

回答

2

你得到一個異常的原因是,當你沒有可用的連接時,你創建一個新的連接並返回它,而無需調用Monitor.Enter()。這意味着您將獲取該對象引用的非遞歸SyncLock,釋放該鎖,然後嘗試對您從未參與過的其他鎖調用Monitor.Exit()。

對於將連接添加到池中的方式,您也有潛在的競爭條件。另一個線程可能會很好地鎖定剛剛創建的連接(通過Monitor.TryEnter()調用),然後再將其設置爲SyncLock塊以便自己完成。如果您在將連接返回到池之前關閉連接(這是一個好主意),那麼當您的創建線程實際上可以使用它時,則會出現連接處於不良狀態。

我實際上建議你不要試圖編寫自己的連接池。您當前的代碼沒有任何內容,這表明您不能只使用System.Data.SqlClient.SqlConnection,而是已經爲您處理連接池。

+0

該類確實會執行連接池,但是它至少會爲每個唯一連接字符串打開1個連接,因此Microsoft文檔說明了這一點。所以它有時拋出異常的原因是當它產生一個新的,我不使用監視器來鎖定它,我知道有一些重要的我失蹤了。在返回池之前關閉連接更有利於什麼? – Jrud

+1

我認爲你誤讀了,它會爲每個唯一的連接字符串創建一個_pool_。每個池默認有100個潛在連接。 [Here](http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx)是MSDN文檔的鏈接,請查看標題爲Pool Creation And Assignment的部分。 –

+1

至於關閉連接,您希望初始化您取出的資源並在您放回時清理它們。如果您的連接因不管出於什麼原因而處於不良狀態,並且將其重新放回池中以供重新使用,這可以確保其他代碼需要良好的連接將會遇到問題,即他們不負責並且無法知道關於。此外,這意味着,無論實際使用量如何,您都可以與SQL Server建立N個連接,這些連接只佔用空間並獨佔可用的SQL Server連接。 –