如何处理/杀死C#中的锁定线程

时间:2014-11-08 14:24:34

标签: c# multithreading thread-safety

我已经看到很多关于如何杀死锁定线程的问题,而且我看到的每个答案都说不会杀死线程,甚至不使用Thread.Abort,只需使用良好的编程习惯来处理线程应该停止。

我的问题是,我被困在使用一个我无法控制的旧第三方库,并且偶尔会锁定,使用相当多的100%CPU并且永不放弃。 Thread.Abort不会阻止这一点。我找不到任何阻止它的方法。

我发现最好的“解决方法”是使用委托和.AsyncWaitHandle.WaitOne(10000,false);

代码将在超时后从这一点继续,但仍然运行的任何线程继续运行并耗尽我的所有CPU。

我该如何处理这种情况?如果这个第三方库锁定,我需要一种方法来杀死它。

谢谢你的时间, 本

2 个答案:

答案 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 会立即杀死一个线程。