我可以不打电话吗?在线程中使用 OleDBCommand 或 OleDbDataAdapter 时,是否要释放它?

Can I refrain from calling .Dispose on an OleDBCommand or an OleDbDataAdapter when it's used in a Thread?

提问人:DinahMoeHumm 提问时间:8/16/2023 更新时间:8/18/2023 访问量:52

问:

当我们决定使用线程在后台填充某些数据集以使我们的应用程序从最终用户的角度更具响应性时,我们在使用 RaceOnRCWCleanups 时遇到了一些问题。

经过一番调查,我们发现,当我们使用 OleDbCommand 和 OleDbDataAdapter 填充 DataSet 时,以及当我们从后台线程调用它时,会发生这种情况。

当我们从主 UI 线程调用它时,没有问题。如果在尝试填充 DataSet 时出现任何失败,我们只需确保所有这些对象都已整理、处置并设置为 null,然后再退出填充 DataSet 的过程。

但是,当我们从线程调用相同的过程时,我们发现有时会导致 RaceOnRCWCleanup 问题。

我可以通过简单地检查使问题“消失”

System.Threading.Thread.CurrentThread.IsBackground

如果这是假的,我根本不会打电话.在 OleDbDataAdapter 和 OleDbCommand 上释放。我只将它们设置为 null,其余的留给垃圾回收器。当我这样做时,我不再收到 RaceOnRCWCleanup 错误。

问题是:我是否在这里为失败做好了准备?我不能给你一个非常具体的例子,但我只想得到一些一般性的建议。

即使垃圾收集器会花它的甜蜜时间,并且可能需要很长时间才能最终清除我不处理的对象,但这是我可以忍受的。然而,如果这些现在将无限期地徘徊,并且永远不会被清除,那么我可能会为未来的新问题做好准备。

因此,我真的需要听取具有 OleDbDataAdapter 和 OleDbCommand 对象专业知识的人的意见,以及 .NET Framework 如何处理这些对象(如果它们未显式释放)。

非常感谢。

C# vb.net 多线程 oledbcommand oledbdataadapter

评论

3赞 Ralf 8/16/2023
在典型的使用模式中,不需要在线程之间共享任何数据库内容,你在这里做这种事情吗?喜欢共享连接吗?
5赞 JonasH 8/16/2023
在后台线程上运行并不能免除您释放对象的需要。只要您一次只从单个线程使用它,大多数对象都可以正常工作。某些对象只能从创建它的线程中使用(与大多数 UI 对象一样)。但是 OleDB 是围绕 COM 构建的,并且可能有一些关于线程的特殊规则。这应该被记录下来。但我尽量避免任何与COM相关的内容,因为整个系统在我看来过于复杂、脆弱,而且记录很少。
0赞 DinahMoeHumm 8/16/2023
@JonasH我担心有人会说这样的话,希望他们不会。好的,我会去进一步挖掘。我刚才发现,在对命令和数据适配器执行相同的操作之前,我正在关闭并释放 Connection 对象。这在我看来并不可怕!:-)
1赞 DinahMoeHumm 8/16/2023
@Ralf,不,谢天谢地。每个线程都有自己的连接,并执行自己的 OleDb“工作”。但正如我向 JonasH 提到的,我确实在我做事的顺序中发现了一个潜在的问题。我发现许多过程在尝试对命令和数据适配器执行相同操作之前关闭并处置了连接,因此我认为仅此一项可能是我获得 RaceOnRCWCleanups 的一个很好的理由......所以我可能一直吠错了树!
0赞 Tu deschizi eu inchid 8/16/2023
您可能对以下内容感兴趣: using 语句 - 确保正确使用一次性物品

答:

4赞 JonasH 8/18/2023 #1

您需要释放对象 所有可处置对象†,无论是否在后台线程上运行。您还需要确保没有以非线程安全的方式使用任何对象。在 OleDb 的情况下,最安全的方法是在同一线程上创建连接、命令和适配器。

要记住的另一件事是,对象应按照创建对象的相反顺序进行处置,即使发生异常也应进行处置。使用 using 语句最容易完成此操作:

public void ReadMyData(string connectionString)
{
    string queryString = "SELECT OrderID, CustomerID FROM Orders";
    using var connection = new OleDbConnection(connectionString);
    using var command = new OleDbCommand(queryString, connection);
    connection.Open();
    using var reader = command.ExecuteReader();

   while (reader.Read())
   {
       Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1));
   }
}

改编自 MS OleDbCommand 示例。这应确保保证每个对象都得到释放,并以正确的顺序释放,无论任何操作是否失败。如果有任何拥有 IDisposable 对象的自定义类,则需要使该类 IDisposable 成为 IDisposable。

† “始终处置”规则有一些例外,值得注意的例子是 和 ,处置这些并没有什么坏处,但我不会花太多精力来确保它完成。MemoryStreamTask