线程或任务(停止挂起的单行代码)

问题描述 投票:0回答:2

线程/任务和异步处理新手... 我有一个尝试获取文件的进程,但是,如果该文件受密码保护,则对

GetDocument
的调用永远不会返回,并挂起服务。
在我看过的所有“示例”代码和教程中,线程过程似乎是包装在某种循环中的多行,因此允许在 while 子句或其他子句中取消的能力。
由于尝试执行单行代码,任务是否会更适合? 还有其他建议吗?

public class ServerClass
{
    public static PageData pageData;
    public static ImageDataProvider idp;
    public static Rendition rend;
    
    public static void AcquireRendition(object obj) 
    {
        CancellationToken ct = (CancellationToken)obj;
        while ((!ct.IsCancellationRequested) || (pageData == null)) 
        {
            pageData = idp.GetDocument(rend);   ////line failing to return
        }
    }
}
c# multithreading task .net-4.5
2个回答
1
投票

您确定没有允许您传递取消令牌的 API 吗?您可以使用其他客户端/库吗?通常没有安全的方法来阻止“挂起”的呼叫。即使使用“同步”阻塞 I/O 方法也是一个非常糟糕的主意。然后,通过将整个对象作为静态字段来访问,而不考虑共享(ImageDataProvider是线程安全的吗?),情况会变得更糟。

如果您确实无法获得更好的 API,您可能必须将整个事情分离到不同的进程中 - 您

可以

终止。 任务绝对不能被终止(它们完全依赖于合作取消),并且线程非常不安全且不可靠,会出现“粗鲁”的中止(再次强调,合作取消是首选)。您不知道会导致什么样的损坏,并且编写可以很好地处理异步异常的代码几乎是不可能的。你当然不能指望一个甚至不提供合作取消机会的图书馆。


0
投票

Thread.Interrupt

 方法中断可能卡住的线程。下面是一个辅助方法 
RunInterruptible,它观察
CancellationToken
,在令牌被取消时中断当前线程,并传播
OperationCanceledException
。它与新 API 具有相同的签名
ControlledExecution.Run
(.NET 7,
源代码
): public static void RunInterruptible(Action action, CancellationToken cancellationToken) { if (action == null) throw new ArgumentNullException("action"); cancellationToken.ThrowIfCancellationRequested(); bool completedSuccessfully = false; try { try { using (CancellationTokenRegistration _ = cancellationToken .Register(arg => ((Thread)arg).Interrupt(), Thread.CurrentThread)) action(); completedSuccessfully = true; } finally { Thread.Sleep(0); } // Last chance to be interrupted } catch (ThreadInterruptedException) { if (completedSuccessfully) return; cancellationToken.ThrowIfCancellationRequested(); throw; } }

使用示例:

RunInterruptible(() => pageData = idp.GetDocument(rend), ct);

如果线程没有陷入等待状态,而是不受控制地旋转,则
Thread.Interrupt

将不起作用。在这种情况下,您可以尝试使用下面的

RunAbortable
方法。在采取这一严厉措施之前,请确保您
充分了解在生产环境中使用
Thread.Abort方法的影响
// .NET Framework only [Obsolete("The RunAbortable method may prevent the execution of static" + " constructors and the release of managed or unmanaged resources," + " and may leave the application in an invalid state.")] public static void RunAbortable(Action action, CancellationToken cancellationToken) { if (action == null) throw new ArgumentNullException("action"); cancellationToken.ThrowIfCancellationRequested(); bool completedSuccessfully = false; try { try { using (CancellationTokenRegistration _ = cancellationToken .Register(arg => ((Thread)arg).Abort(), Thread.CurrentThread)) action(); completedSuccessfully = true; } finally { Thread.Sleep(0); } // Last chance to be aborted } catch (ThreadAbortException) { if (completedSuccessfully) { Thread.ResetAbort(); return; } if (cancellationToken.IsCancellationRequested) { Thread.ResetAbort(); throw new OperationCanceledException(cancellationToken); } throw; // Redundant, the ThreadAbortException is rethrown anyway. } }

© www.soinside.com 2019 - 2024. All rights reserved.