c# - 当线程不活动时释放资源

标签 c# multithreading backgroundworker

我正在使用 BackgroundWorker 并在其中使用 foreach 循环,我在其中创建新线程,等待它完成,然后报告进度并继续 foreach 循环。这就是我要说的:

private void DoWork(object sender, DoWorkEventArgs e) {
            var fileCounter = Convert.ToDecimal(fileNames.Count());
            decimal i = 0;
            foreach (var file in fileNames) {
                i++;
                var generator = new Generator(assembly);

                var thread = new Thread(new ThreadStart(
                        delegate() {
                            generator.Generate(file);
                        }));
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
                while (thread.IsAlive); // critical point
                int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100));
                backgroundWorker.ReportProgress(progress);
            }
        }

问题是线程结束后(“临界点”行通过后)内存没有被释放。我以为当线程不活着的时候,它关联的所有资源都会被释放。但显然这不是真的。 谁能向我解释为什么以及我做错了什么。 谢谢。

最佳答案

您设法关闭了告诉您您做错了什么的组件。但是,您实际上并没有解决问题。不支持线程的组件需要 STA,单线程单元。因此它的所有方法都是从同一个线程调用的,即使调用是在另一个线程上进行的。 COM 负责将调用从一个线程编码到另一个线程。 STA 线程通过泵送消息循环使这成为可能。

然而,您所做的是创建另一个 线程并对其进行调用,这与创建生成器 对象的线程不同。这并没有解决问题,它仍然是线程不安全的。 COM 仍会编码调用。

最重要的是您在其上创建生成器 对象的线程。因为它是一个单元线程对象,所以它必须在 STA 线程上创建。 Windows 应用程序中通常只有一个,即程序的主线程,也就是通常所说的 UI 线程。如果您在不是 STA 的 .NET 工作线程上创建它,就像您在此处所做的那样,那么 COM 将介入并创建一个 STA 线程本身,为组件提供一个好客的家。这很好,但通常不受欢迎。

天下没有免费的午餐,您不能神奇地让一段明确表示它不支持线程的代码块(注册表中的 ThreadingModel 键)表现得像它一样。下一个最佳选择是创建一个 STA 线程并在其上运行所有 代码,包括 COM 对象创建。请注意,您通常必须使用 Application.Run() 来泵送消息循环,许多 COM 服务器假定有一个可用的。特别是当他们告诉您需要 STA 线程时。您会注意到它们在行为不当、方法调用死锁或不引发事件时会这样做。

关于您的原始问题,这是标准的 .NET 行为。垃圾收集器在需要时运行,而不是在您认为应该运行的时候运行。您可以使用 GC.Collect() 覆盖它,但很少需要这样做。尽管对您的情况来说这可能是一个快速修复,但 COM 会为每个文件创建一个新线程。给 generator 一个家的 STA 线程。使用 Debug + Windows + Threads 来查看它们。在 COM 对象被销毁之前,这些线程不会停止。这需要终结器线程才能运行。当有超过两千个文件时,您的代码也会消耗所有可用内存和 OOM 炸弹,也许有足够的理由寻找真正的修复。

关于c# - 当线程不活动时释放资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5948075/

相关文章:

c# - WCF 服务为每个新请求创建一个新线程

c# - C#-获取以编程方式在Windows启动时运行的应用程序列表

java - 由于编译器重新排列代码可能导致同步问题

ios - CPU 运行率超过 100%

c# - 以并行方式将项目添加到 ListBox

c# - 将 HTML 转换为 PDF dink 到 pdf 时 CSS 转换和写入模式属性的问题

C# 错误 CS0052,可访问性不一致

java - 简单的 Java 线程 TCP 服务器线程

c# - 后台 worker - 使用字符串数组报告进度

c# - 调用线程无法访问此对象,因为另一个线程拥有它