2

私は自分のサービスとその SQL データベースの間で対話するために書いているマルチ スレッド サービス用に、もう少し効率的な接続プールを構築しています。基本的に要約すると、クラスに次のコードがあります。

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

したがって、このコードは非常にうまく機能します。異なるスレッドで 500 の select ステートメントをコンピューターが実行できる速さで実行でき、8 つの異なる接続を開きます (おそらくコンピューターの速度が原因で、遅い PC はより多く開く可能性があります)。問題は、DBSelect 関数で、Try/Catch で囲まれた行でモニターの Enter を解放することです。同期クロックを終了すると、オブジェクトのロックがドロップされることがあるため (この場合、行は不要で例外がスローされることがあります)オブジェクトはまだロックされており、その行を実行しなくても永続的にロックされたままになります (この場合、オブジェクトはそれを使用して正常に通過します)。なぜそれを解放するのか、時には解放しないのか、一生わからない. 何か案は?

4

1 に答える 1

2

例外が発生する理由は、使用可能な接続がない場合に、新しい接続を作成し、それに対して Monitor.Enter() を呼び出さずに返すためです。これは、そのオブジェクト参照に対して非再帰的な SyncLock を取得し、そのロックを解放してから、最初に取得したことのない追加のロックで Monitor.Exit() を呼び出そうとすることを意味します。

また、プールに接続を追加する方法を取り巻く潜在的な競合状態もあります。別のスレッドが、作成した接続を (Monitor.TryEnter() 呼び出しを介して) SyncLock ブロックにして自分で取得する前に、ロックを取得する可能性があります。接続をプールに戻す前に閉じている場合 (これは良い考えです)、作成中のスレッドが実際にそれを使用するようになると、接続が悪い状態になります。

実際には、独自の接続プールを作成しようとしないことをお勧めします。現在のコードには、接続プールを既に処理している System.Data.SqlClient.SqlConnection を代わりに使用できないことを示唆するものは何もありません。

于 2011-06-29T23:57:21.200 に答える