我已经看到很多关于如何杀死锁定线程的问题,而且我看到的每个答案都说不会杀死线程,甚至不使用Thread.Abort,只需使用良好的编程习惯来处理线程应该停止。
我的问题是,我被困在使用一个我无法控制的旧第三方库,并且偶尔会锁定,使用相当多的100%CPU并且永不放弃。 Thread.Abort不会阻止这一点。我找不到任何阻止它的方法。
我发现最好的“解决方法”是使用委托和.AsyncWaitHandle.WaitOne(10000,false);
代码将在超时后从这一点继续,但仍然运行的任何线程继续运行并耗尽我的所有CPU。
我该如何处理这种情况?如果这个第三方库锁定,我需要一种方法来杀死它。
谢谢你的时间, 本
答案 0 :(得分:5)
如果您需要一般性答案,请使用易于锁定的代码进行单独处理。根据需要杀死并重新启动该过程。随着您对所面临的确切问题的更多了解,可能会有更好的解决方案。
答案 1 :(得分:1)
我会创建一个单独的应用程序域来运行一个不受信任的程序集,或者不像你的情况那样不时地运行。可以随时卸载应用程序域,它将在您的代码和外部代码之间创建一个边框。这是一个小例子。让我们从包含错误代码的外部程序集开始:
public class Processor
{
public void Run()
{
while (true) { /* ... */ }
}
}
现在我们需要一个类来加载 BadAssembly.dll ,创建 Processor 的实例并在单独的线程中调用 Run 方法为了不阻止你的应用程序的主线程。
public class Loader : MarshalByRefObject
{
public bool IsCompleted { get; private set; }
public bool IsFaulted { get; private set; }
public void LoadAndRunBadAssembly()
{
var ass = Assembly.LoadFrom("BadAssembly.dll");
var c = (Processor)ass.CreateInstance("BadAssembly.Processor");
Task.Factory.StartNew(() =>
{
try
{
c.Run();
IsCompleted = true;
}
catch (Exception)
{
IsFaulted = true;
}
}, TaskCreationOptions.LongRunning);
}
}
如果外部代码已经完成处理,则需要IsCompleted 和 IsFaulted 属性以告知我们。 Loader 派生自 MarshalByRefObject ,因为它的代码将在我们创建的单独域中执行。这是一个测试 Loader 类的代码:
var appDomain = AppDomain.CreateDomain("Loader");
try
{
//Here I assume that Loader class is in the same assembly as this code
var loader = (Loader)appDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof (Loader).FullName);
loader.LoadAndRunBadAssembly();
Console.WriteLine("Waiting...");
Thread.Sleep(20000); //This simulates waiting for external code
if (loader.IsCompleted)
Console.WriteLine("Processing has finished");
else if (loader.IsFaulted)
Console.WriteLine("There was an error");
else
Console.WriteLine("It lasts too long");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
AppDomain.Unload(appDomain);
}
<强>更新强>
我刚刚意识到,为了阻止域中的线程, AppDomain.Unload 方法使用 Abort 方法。这意味着您在尝试卸载域时可能会收到CannotUnloadAppDomainException异常。它会发生,因为不能保证 Abort 会立即杀死一个线程。