在后台线程中使用OdbcDataAdapter.Fill时,在非托管代码中访问冲突异常

时间:2014-04-11 17:00:05

标签: c# .net wpf multithreading odbc

我正在尝试使用Threads来尝试学习一些关于它们的知识。我写了一个小的WPF应用程序,它开始使用后台线程在一个时间间隔内轮询ODBC源,通过OdbcDataAdapter.Fill将数据检索到DataTable并将其写入CSV文件。

每隔一段时间,该应用就会遇到AccessViolationException。时间有所不同,有时可能会在遇到它之前运行几天,有时只需要一天。到目前为止,它还没有发生过UI交互的结果。

线程(堆栈跟踪中的LoggingThread)是让MainWindow通过调用MyApp来控制它,MyApp通过ManualResetEvents和CancellationTokenSource管理LoggingThread。 LoggingThread本身运行由上述ManualResetEvents管理的连续循环。

之前我已经在其他单线程项目中成功使用过DataAdapter,所以我想这可能是我如何处理LoggingThread设置发生此异常的条件,因为轮询代码非常简单:

if (!this._cancelToken.IsCancellationRequested)
{
    using (OdbcConnection conn = new OdbcConnection(this.connStr))
    {
        using (var adapter = new OdbcDataAdapter(this.sql, conn))
        {
            try
            {
            int rows = adapter.Fill(table);
            }
            catch() { // log Exception(s) }
            finally
            {
                adapter.Dispose();
                conn.Close();
                conn.Dispose();
            }
        }
        conn.Close();
    }        
}

是什么导致这个?我可以采取一些缓解措施来避免它吗?

如果您需要其他代码段以更全面地了解这一点,请告诉我。

例外情况:

Exception Info: System.AccessViolationException
Stack:
   at System.Data.Common.UnsafeNativeMethods.SQLMoreResults(System.Data.Odbc.OdbcStatementHandle)
   at System.Data.Odbc.OdbcStatementHandle.MoreResults()
   at System.Data.Odbc.OdbcDataReader.NextResult(Boolean, Boolean)
   at System.Data.Odbc.OdbcDataReader.Close(Boolean)
   at System.Data.Odbc.OdbcDataReader.Dispose(Boolean)
   at System.Data.Common.DbDataReader.Dispose()
   at System.Data.Common.DbDataAdapter.FillInternal(System.Data.DataSet, System.Data.DataTable[], Int32, Int32, System.String, System.Data.IDbCommand, System.Data.CommandBehavior)
   at System.Data.Common.DbDataAdapter.Fill(System.Data.DataTable[], Int32, Int32, System.Data.IDbCommand, System.Data.CommandBehavior)
   at System.Data.Common.DbDataAdapter.Fill(System.Data.DataTable)
   at MyApp.LoggingThread.PollServer(System.Data.DataTable)
   at MyApp.LoggingThread.LoggingHandler()
   at MyApp.MyApp.<StartProcessing>b__0()
   at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
   at System.Threading.ExecutionContext.runTryCode(System.Object)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

修改

这是堆栈跟踪中引用的LoggingHandler()方法,也许它可以提供帮助。

DataTable table = new DataTable();
while (true)
{

   this.pauseEvent.WaitOne(Timeout.Infinite);
    if (this.stopEvent.WaitOne(0))
    {
        break;
    }

    PollServer(table);

    if (table != null && table.Rows.Count > 0)
    {
         WriteData(table);
         table.Clear();
    }
    else
    {
         table = new DataTable();
    }

    if (!this._cancelToken.IsCancellationRequested)
    {
        this.loopingEvent.WaitOne(this.delaySpan);
    }
}

2 个答案:

答案 0 :(得分:0)

using语句仅适用于一次性对象。所以结果......

using (OdbcConnection conn = new OdbcConnection(this.connStr))
{
    //...
}

using语句转换为:

OdbcConnection conn = null;
try
{
     conn = new OdbcConnection(this.connStr);
     // other code
}
finally
{
    if (conn != null)
        conn.Dispose();
}

您对Dispose()的多次和不必要的调用可能会出现问题。特别是在将连接放置在嵌套的try / finally块中后,在连接上调用Close()的位置。但是,我不相信这是完整的故事。需要更多代码来确定其他问题。

答案 1 :(得分:0)

我有同样的问题,我正在使用&#34;使用&#34;但仍然失败了。我意识到这是以下几行,

使用cmd As System.Data.Odbc.OdbcCommand = objConn.CreateCommand() 结束使用

我的问题是因为我正在通过连接对象,以保持连接打开,我正在创建大量的ObdcCommand ...对象

希望这会有所帮助。