我正在尝试使用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);
}
}
答案 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 ...对象
希望这会有所帮助。