为什么这段代码总是会出现SynchronizationLockException?

5
这段代码有什么问题吗?
我总是会收到一个“Object synchronization method was called from an unsynchronized block of code”异常。
System.Threading.Monitor.Exit(m_sqlConnection)

但是......无论我将Monitor语句放在try-catch-finally块内还是外面,以任何组合方式,我总是会得到这个异常。

也就是说,在编译代码后。如果我在第一次出现异常后再次运行它,它就可以正常工作......总是在重新编译后出现异常...

Public Shared Function GetDataTable(ByRef strSQL As String, ByRef dt As System.Data.DataTable, Optional ByRef strTableName As String = "ThisTable") As Integer
            Dim daQueryTable As System.Data.SqlClient.SqlDataAdapter = Nothing



            Try
                System.Threading.Monitor.TryEnter(m_sqlConnection, 5000)

                If isDataBaseConnectionOpen() = False Then OpenSQLConnection()


                daQueryTable = New System.Data.SqlClient.SqlDataAdapter(strSQL, m_sqlConnection)
                dt = New System.Data.DataTable(strTableName)

                daQueryTable.Fill(dt)
            Catch ex As Exception
                Log(ex)
                Return -1
            Finally
                m_sqlConnection.Close()
                System.Threading.Monitor.Exit(m_sqlConnection)
                daQueryTable.Dispose()
                daQueryTable = Nothing
            End Try

            Return dt.Rows.Count
        End Function ' GetDataTable

C#版本:

public static int GetDataTable(ref string strSQL, ref System.Data.DataTable dt, ref string strTableName = "ThisTable")
{
    System.Data.SqlClient.SqlDataAdapter daQueryTable = null;



    try {
        System.Threading.Monitor.TryEnter(m_sqlConnection, 5000);

        if (isDataBaseConnectionOpen() == false)
            OpenSQLConnection();


        daQueryTable = new System.Data.SqlClient.SqlDataAdapter(strSQL, m_sqlConnection);
        dt = new System.Data.DataTable(strTableName);

        daQueryTable.Fill(dt);
    } catch (Exception ex) {
        Log(ex);
        return -1;
    } finally {
        m_sqlConnection.Close();
        System.Threading.Monitor.Exit(m_sqlConnection);
        daQueryTable.Dispose();
        daQueryTable = null;
    }

    return dt.Rows.Count;
} // GetDataTable
2个回答

10

你正在调用TryEnter,但忽略了结果 - 所以即使你没有拥有它,你也将尝试退出监视器。如果TryEnter返回false,你应该采取适当的措施,比如退出该方法。


嗯,换句话说,TryEnter在超时后不会抛出异常。该死...但是找到了错误:我在OpenSQLConnection上锁定了,但从未解锁。 - Stefan Steiger
4
@Quandary:不,它返回一个值。一定要查看文档 :) 无论如何,你的代码仍然有问题——你仍然会进入finally块并尝试关闭连接,然后退出锁定(释放锁)。实际上,如果你没有获取锁就关闭连接会很糟糕——你可能会关闭其他人正在使用的连接... - Jon Skeet

-1

由于lock语句Monitor.EnterMonitor.Exit的快捷方式,我建议您简单地使用lock语句并忽略Monitor类。


8
由于锁定语句没有超时(如果我错了,那么它是非常非常高的),例如TryEnter,因此我建议您使用TryEnter而不是lock。 - Stefan Steiger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接