如何在C#中处理/终止锁定线程

本文关键字:终止 锁定 线程 处理 | 更新日期: 2023-09-27 18:29:51

我看到了很多关于如何杀死锁定线程的问题,我看到的每个答案都说不要杀死线程,甚至不要使用线程。中止,只要使用良好的编程实践来处理线程何时应该停止。

我的问题是,我一直在使用一个我无法控制的旧第三方库,偶尔会出现这种情况,使用几乎100%的CPU,而且从未放弃。线程。中止不会停止此操作。我找不到任何方法来阻止这件事。

我找到的最好的"变通方法"是使用委托和.AncWaitHandle.WetOne(10000,false);

超时后,代码将从这一点开始继续,但无论哪个线程在运行,都会继续运行并耗尽我所有的CPU。

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

感谢您抽出时间,Ben

如何在C#中处理/终止锁定线程

如果您需要一个通用的答案,请使用倾向于锁定的代码创建一个单独的进程。根据需要终止并重新启动进程。随着对你所面临的确切问题有了更多的了解,可能会有更好的解决方案。

我会创建一个单独的应用程序域来运行一个不受信任的程序集,或者只是在您的情况下不工作。应用程序域可以随时卸载,它将在您的代码和外部代码之间创建边界。这里有一个小例子。让我们从包含错误代码的外部程序集开始:

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);
    }
} 

需要IsCompletedISFaultdoader是从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会立即终止线程。