【发布时间】:2014-12-30 18:23:22
【问题描述】:
我有一些任务(nWorkers = 3):
var taskFactory = new TaskFactory(cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning, TaskScheduler.Default);
for (int i = 0; i < nWorkers; i++)
{
var task = taskFactory.StartNew(() => this.WorkerMethod(parserItems, cancellationTokenSource));
tasks[i] = task;
}
任务调用的方法如下:
protected override void WorkerMethod(BlockingCollection<ParserItem> parserItems, CancellationTokenSource cancellationTokenSource)
{
...log-1...
using (var connection = new OracleConnection(connectionString))
{
OracleTransaction transaction = null;
try
{
cancellationTokenSource.Token.ThrowIfCancellationRequested();
connection.Open();
...log-2...
transaction = connection.BeginTransaction();
...log-3...
using (var cmd = connection.CreateCommand())
{
foreach (var parserItem in parserItems.GetConsumingEnumerable(cancellationTokenSource.Token))
{
cancellationTokenSource.Token.ThrowIfCancellationRequested();
try
{
foreach (var statement in this.ProcessRecord(parserItem))
{
cmd.CommandText = statement;
try
{
cmd.ExecuteNonQuery();
}
catch (OracleException ex)
{
...log-4...
if (!this.acceptedErrorCodes.Contains(ex.Number))
{
throw;
}
}
}
}
catch (FormatException ex)
{
log.Warn(ex.Message);
}
}
if (!cancellationTokenSource.Token.IsCancellationRequested)
{
transaction.Commit();
}
else
{
throw new Exception("DBComponent has been canceled");
}
}
}
catch (Exception ex)
{
...log-5...
cancellationTokenSource.Cancel();
if (transaction != null)
{
try
{
transaction.Rollback();
...log-6...
}
catch (Exception rollbackException)
{
...log-7...
}
}
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
connection.Close();
...log-8...
}
}
...log-9...
}
有一个 ParserItem 对象的生产者,这些是消费者。通常它工作正常,有时会出现 Oracle 连接超时,但在这些情况下,我可以看到异常消息并且一切都按设计工作。
但有时该过程会卡住。当它卡住时,在日志文件中我可以看到 log-1 消息,然后(大约 15 秒后)我看到 log-8 消息,但是让我抓狂的是为什么我看不到异常消息日志-5 也不是 log-9 消息。 由于从不调用 cancelTokenSource.Cancel() 方法,因此有界集合的项目生产者会被卡住,直到两小时后超时。
它是为 NET Framework 4 编译的,我使用 Oracle.ManagedDataAccess 库进行 Oracle 连接。
任何帮助将不胜感激
最好的问候, 谢谢
【问题讨论】:
-
您是否有可能只是遇到数据库端死锁?我建议使用提示告诉 ORACLE 您对数据读取和更新的首选锁定策略。
-
您需要进行挂起转储。我推荐使用procdump。然后,您可以使用 SOS.dll 将转储加载到 WinDBG 中并开始查看。有很多很棒的入门教程。
-
@Darek 我知道在数据库端死锁的情况下,我应该捕获并查看 Oracle 异常,而不是只查看 finally 子句的执行。是这样吗?还是我错过了什么
-
您可能遇到了一些内存死锁,因为在您的代码中,您从 catch 块中取消,这本身会引发异常。底部,行,错误的代码。尝试清理,然后再次调查。
标签: c# oracle exception task producer-consumer