独自のスレッドで動作する多くのサードパーティ DLL を使用する WPF アプリケーションがあります。
これらの DLL の一部にはメソッドがありSTOP()
ます。
私はThread.Sleep(1000)
各SomeObject.Stop()
方法の後に使用しています...
とにかく、アプリケーションを終了すると、一部のスレッドがまだメモリ内に残っています。
この問題を解決する方法はありますか?
独自のスレッドで動作する多くのサードパーティ DLL を使用する WPF アプリケーションがあります。
これらの DLL の一部にはメソッドがありSTOP()
ます。
私はThread.Sleep(1000)
各SomeObject.Stop()
方法の後に使用しています...
とにかく、アプリケーションを終了すると、一部のスレッドがまだメモリ内に残っています。
この問題を解決する方法はありますか?
つまり、基本的には、サードパーティのライブラリで問題が発生し、必要なときに適切にクリーンアップできません。さらに、その上に、アプリケーションを終了したい場合でも、アプリケーションを実行し続けるための一連のフォアグラウンドスレッドがスピンアップします。
例として、このようなアプリケーション
private static void Main(string[] args)
{
var t = new Thread(() =>
{
while (true)
{
}
}) {Name = "test"};
t.Start();
Console.WriteLine("Exited");
}
t
前景のスレッドな ので、永遠に座ります。
ProcessExplorerで再確認してみましょう。これがデモアプリの更新バージョンで、ピンボークしてネイティブスレッド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を教えてください。プロセスエクスプローラーで私は今見ることができます:
mainがすでに終了しているにもかかわらず、whileループが原因でスレッド8228が激しく回転していることは明らかです。
一般的に、ユーザーRobHardyは正しいです。スレッドを制御する場合は、常に物事を追跡して自分で管理する必要がありますが、スレッドハンドルにアクセスできないため、ここでは問題が発生していると思います。
あなたはすべてを殺そうとすることができます(しかし、とにかくそれを試したとき、それは私にとって実際にはうまくいきませんでした)、しかしそれをすることは信じられないほど危険であるように思われるので私は本当にこれをしません。他の投稿から情報をコピーするだけで、例は次のように述べています。
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);
}
これは私のために働いた。
3番目のオプションは、可能であれば、ライブラリを修正して、バックグラウンドスレッドを作成するか、適切にクリーンアップすることです。サードパーティのアイテムをクリーンアップしないことで、潜在的な破損可能な副作用を開いたままにしないため、これが最良のオプションです。ただし、ライブラリはクローズドソースであるため、これを行っていないことを前提としています。
スレッドをコレクションに追加するか、ThreadPool
各スレッドで、必ずThreadAbortException
の最後の終了点で、Main()
スレッドのコレクションを調べて、Abort()
それぞれを呼び出します。