所以基本上你面临的问题是 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 方项目而留下任何潜在的可破坏的副作用。不过,我假设您没有这样做,因为该库是封闭源代码。