我有一个 WPF 应用程序,它使用许多在自己的线程中工作的第三方 DLL。
其中一些 DLL 有方法STOP()。
我Thread.Sleep(1000)在每种SomeObject.Stop()方法之后都使用...
无论如何,当我终止应用程序时,一些线程仍在内存中。
任何线索如何解决这个问题?
我有一个 WPF 应用程序,它使用许多在自己的线程中工作的第三方 DLL。
其中一些 DLL 有方法STOP()。
我Thread.Sleep(1000)在每种SomeObject.Stop()方法之后都使用...
无论如何,当我终止应用程序时,一些线程仍在内存中。
任何线索如何解决这个问题?
因此,基本上,您面临的问题是 3rd 方库在应该清理的时候没有很好地清理,最重要的是,它启动了一堆前台线程,即使您希望它终止,它也能保持您的应用程序运行。
例如,像这样的应用程序
private static void Main(string[] args)
{
    var t = new Thread(() =>
        {
            while (true)
            {
            }
        }) {Name = "test"};
    t.Start();
    Console.WriteLine("Exited");
}
将永远坐在那里,因为t它是一个前台线程。  
让我们仔细检查一下流程资源管理器。这是我们的演示应用程序的更新版本,我们可以调用它并获取本机线程 ID。
internal class Program
{
    [DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    [DllImport("kernel32.dll")]
    static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);
    [DllImport("kernel32.dll")]
    static extern int GetCurrentThreadId();
    private static void Main(string[] args)
    {
        var t = new Thread(() =>
            {
                Console.WriteLine(GetCurrentThreadId());
                while (true)
                {
                }
            }) {Name = "test"};
        t.Start();
        Console.WriteLine("Thread Id " + t.ManagedThreadId);
        Console.WriteLine("Exited");
    }
}
给我本机线程ID。在进程资源管理器中,我现在可以看到:

很明显,由于我的 while 循环,线程 8228 正在疯狂旋转,即使 main 已经退出
一般来说,用户 Rob Hardy 是对的。如果您控制线程,则应该始终跟踪事物并自己管理它们,但是我认为您在这里处于困境中,因为您无权访问线程句柄。
您可以尝试杀死所有东西(但无论如何,当我尝试它时,这对我来说并没有真正起作用),但我真的不会这样做,因为这样做似乎非常危险。只是为了复制另一篇文章中的信息,该示例是这样说的:
internal class Program
{
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);
    private static void Main(string[] args)
    {
        var t = new Thread(() =>
            {
                while (true)
                {
                }
            }) {Name = "test"};
        t.Start();
        Console.WriteLine("Exited");
        Thread.Sleep(TimeSpan.FromSeconds(2));
        foreach (ProcessThread pt in Process.GetCurrentProcess().Threads)
        {
            IntPtr ptrThread = OpenThread(1, false, (uint)pt.Id);
            if (AppDomain.GetCurrentThreadId() != pt.Id)
            {
                try
                {
                    TerminateThread(ptrThread, 1);
                    Console.Out.Write(". Thread killed.\n");
                }
                catch (Exception e)
                {
                    Console.Out.WriteLine(e.ToString());
                }
            }
            else
                Console.Out.Write(". Not killing... It's the current thread!\n");
        }
    }
}
但同样,这并没有阻止我的过程。也许.net 正在等待线程的正确退出,而不仅仅是强制的本机退出?我不知道。我只是表明你可以在技术上(根据链接)可以杀死线程ProcessThread,如果你真的想要(但请不要)
一个更合理的选择是Exit在所有清理之后添加一个带有代码的显式调用(退出代码 0 通常表示干净退出)
private static void Main(string[] args)
{
    var t = new Thread(() =>
        {
            while (true)
            {
            }
        }) {Name = "test"};
    t.Start();
    Console.WriteLine("Exited");
    Environment.Exit(0);
}
这对我有用。
如果可以的话,第三个选项是修复库并让它创建后台线程或让它正确清理。这将是最好的选择,因为您不会因为不清理 3rd 方项目而留下任何潜在的可破坏的副作用。不过,我假设您没有这样做,因为该库是闭源的。
通过将线程添加到集合或使用ThreadPool
在每个线程中确保你处理ThreadAbortException
在你的结尾处的终止点Main(),浏览你的线程集合并调用Abort()每个线程。