【问题标题】:How to delete all threads started within an application?如何删除应用程序中启动的所有线程?
【发布时间】:2013-02-13 12:38:37
【问题描述】:

我有一个 WPF 应用程序,它使用许多在自己的线程中工作的第三方 DLL。

其中一些 DLL 具有方法 STOP()

我在每个SomeObject.Stop() 方法之后都使用Thread.Sleep(1000)...

无论如何,当我终止应用程序时,一些线程仍在内存中。

任何线索如何解决这个问题?

【问题讨论】:

  • 是什么让你说应用程序终止时它们在内存中?那时记忆中什么都没有。你问是因为这些第三方 dll 不是后台线程并且正在阻止优雅的应用程序结束吗?
  • @devshorts 是的,是的。当我关闭我的 WPF 应用程序时,我面临着 TaskManager 下的一些线程。
  • 为什么会出现这个问题?
  • 当你终止应用程序(即进程)时,没有线程会存活。

标签: c# .net wpf multithreading dll


【解决方案1】:

所以基本上你面临的问题是 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 是对的。如果您控制线程,则应该始终跟踪并自己管理它们,但我认为您在这里处于困境中,因为您无权访问线程句柄。

选项 1(但请不要)

您可以尝试kill everything(但无论如何我都尝试过,但我真的不会这样做,因为这样做看起来非常危险。只是为了复制另一篇文章中的信息,示例是这样说的:

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 的线程

选项 2

更合理的选择是在所有清理之后添加一个带有代码的显式 Exit 调用(退出代码 0 通常表示干净退出)

private static void Main(string[] args)
{

    var t = new Thread(() =>
        {
            while (true)
            {
            }
        }) {Name = "test"};

    t.Start();

    Console.WriteLine("Exited");

    Environment.Exit(0);
}

这对我有用。

选项 3

如果可以的话,第三个选项是修复库并让它创建后台线程或让它正确清理。这将是最好的选择,因为您不会因为不清理 3rd 方项目而留下任何潜在的可破坏的副作用。不过,我假设您没有这样做,因为该库是封闭源代码。

【讨论】:

  • 这不是我需要的……但是……看起来很棒! ++++
【解决方案2】:

通过将线程添加到集合或使用 ThreadPool 来跟踪您的线程

确保在每个线程中处理ThreadAbortException

在您的Main() 末尾的终止点,浏览您的线程集合并在每个线程上调用Abort()

【讨论】:

  • 我认为他遇到的问题是这些线程不是由他创建的,而是由他使用的任何库的内部创建的
  • 我做不到。所有这些线程都是一些 DLL,我只有像 START/STOP 这样的公共网络。没有办法像你说的那样追踪它。
  • 在这种情况下,他可以尝试 Process.Threads 集合,该集合将获取当前进程拥有的所有线程,如下所述:msdn.microsoft.com/en-us/library/…
  • @RobHardy 谢谢!我也会检查的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 2014-09-13
相关资源
最近更新 更多