【问题标题】:Is there a way to force the application to run as single threaded?有没有办法强制应用程序作为单线程运行?
【发布时间】:2017-09-02 04:45:26
【问题描述】:

我们支持一个旧项目,并且很可能由于多线程而出现问题。 最初的实施者在执行有问题的部分之前通过执行Thread.sleep 来“修复”它。 解决方法有效,但由于该部分位于循环内,thread.sleep 会增加该部分完成所需的时间。

在上个月,我们一直在尝试降低睡眠值,但我们希望找到根本原因。在我们的调查期间,我们在任何我们认为有帮助的地方对私人对象进行lock。 我们寻找任何可能产生额外线程的东西 - 没有找到。 没有 Thread.start 也没有 ThreadPool 使用。 令我们困惑的是,在调试过程中,我们发现我们的主线程位于大约 8 个其他线程的中间,我们不知道这些线程是谁产生的。 这些是后台线程,所以我首先想到的是线程池,但正如我提到的,代码中没有提到它。

它是 .net 2.0,所以没有 Asyncs。 这只是更大应用程序的一部分,因此它是一个 Windows 服务,但我们将其作为 CMD 运行以便能够轻松调试它。主应用程序本身是一个 Windows 窗体桌面应用程序。 如果有帮助,它还使用 COM+ 组件。

我试过[STA] 而不是[MTA]。 也如上所述锁定。 MemoryBarriers 也是如此。

我们仍然遇到问题。

问题基本上是损坏的数据集和对象中不应出现的空值。 它大约每 25-100 次迭代发生一次,因此重现并不简单,但我们专门针对此问题设计了一个测试来尝试重现它。

所有这些都将我们引向线程问题的方向。

回到原来的问题—— 谁可能通过产生这些额外的线程以及我们如何防止这些线程被创建?

请注意标有红色的线程 - 这些是后台线程,据我们所知,代码中没有提及它们。

截图中疑似线程正在主动修改dataset中的cols。问题是 - 调用线程正在执行的 SetColValueOnRow 函数的方法是典型的并且不使用任何类型的线程。

此应用程序的 CPU 亲和性设置为 1 Core [原始解决方法的一部分]

谢谢

编辑:数据库是 oracle 12c,但我们面临的问题发生在写入数据库之前。 它们通常发生在数据集中,其中每隔几次测试迭代就可以擦除整条记录或其中的一些列

【问题讨论】:

  • 什么类型的应用程序(winforms,服务,...)
  • 这只是更大应用程序的一部分,因此它是一个 Windows 服务,但我们将其作为 CMD 运行以便能够轻松调试它。主应用程序本身是一个 Windows 窗体桌面应用程序。
  • “谁可能通过产生这些额外的线程以及我们如何防止这些线程被创建?”——最初的问题是什么?您的标题是“有没有办法强制应用程序以单线程方式运行?”,这似乎是一个完全不同(且不可行)的问题。一个普通的 .NET 程序有多种原因来创建线程,所以这些可能就是您所看到的。甚至不清楚“强制应用程序作为单线程运行”是什么意思。好像有某种方法可以将多个执行序列塞进一个线程?
  • 您可以尝试运行 Visual Studio 的性能测试工具;记录并记下线程自发出现的情况,就像让物理学家彻夜难眠的量子泡沫一样
  • 你可以做的是在你的类中添加以下自定义注册代码:stackoverflow.com/questions/5726624/… 但设置“Single”而不是“Apartment”(->所有调用将在初始线程上自动序列化) .然后您必须删除/重新创建您的 COM+ 应用程序。 .NET 的 regsvcs 可能不支持自定义线程模型(它只知道“Both”),因此您可能必须手动创建应用程序(使用“组件服务”)或使用一些 VBS/Powershell 脚本

标签: c# multithreading desktop-application com+


【解决方案1】:

我认为您需要调查 Thread.sleep 为何有效。听起来代码本身并没有产生额外的线程,但您必须遍历整个代码库才能找到它 - 包括 COM+ 组件。

所以我要做的第一件事就是在调试中启动程序,然后按 F10 键进入程序。然后打开线程调试窗口,看看您是否看到与问题中给出的线程数大致相同。如果你这样做了,那么这些只是线程池中的线程,你的问题可能与多个线程无关。

如果您没有看到相同数量的线程,请尝试在程序的各个阶段设置断点,看看您是否可以找到创建这些线程的位置。当您找到它们的创建位置时,您可以尝试在此时添加一些锁定。但是,您的问题仍然可能不是由多个线程破坏内存引起的。您应该进行调查,直到您确信问题是由多个线程或其他原因引起的。

我怀疑问题可能与一个或多个 COM+ 组件有关,或者代码可能正在调用某个长时间运行的数据库存储过程。无论如何,我怀疑 Thread.sleep 工作的原因是因为它给了可疑组件足够的时间来完成其操作,然后再开始下一个操作。

如果这个理论是正确的,那么它表明操作之间存在一些交互,并且当 Thread.Sleep 被赋予足够大的值以允许操作完成时 - 不存在交互问题。这也表明可能其中一个 COM+ 组件正在异步执行某些操作。解决方案可能是在 COM+ 组件代码中使用锁或临界区。另一个想法是重新设计导致问题的代码部分以允许同时进行多个操作。

因此,您遇到的问题可能不是由于您正在查看的 C# 代码中的多个线程 - 但可能是由于长时间运行的操作,如果在开始之前没有足够的时间来完成,有时会失败下一个操作。这可能是由于 C# 代码中有多个线程,也可能不是。

【讨论】:

  • 你是对的 - 这是我正在尝试做的事情之一。该应用程序庞大且不简洁,因此显然这需要很长时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-15
  • 2021-10-27
  • 2013-02-07
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多