如何处理第三方代码中的死锁

Ack*_*ari 5 c# deadlock .net-5

我们有一个第三方方法Foo,有时会因未知原因而陷入死锁。

我们正在执行一个单线程 tcp 服务器,并每 30 秒调用此方法来检查外部系统是否可用。

为了缓解第三方代码中的死锁问题,我们将 ping 调用放在Task.Runto 中,以便服务器不会死锁。

喜欢

async Task<bool> WrappedFoo()
{
    var timeout = 10000; 

    var task = Task.Run(() => ThirdPartyCode.Foo());
    var delay = Task.Delay(timeout);

    if (delay == await Task.WhenAny(delay, task ))
    {
        return false;
    }
    else
    {
        return await task ;
    }
}
Run Code Online (Sandbox Code Playgroud)

但这(在我们看来)有可能导致空闲线程的应用程序匮乏。因为如果一次调用ThirdPartyCode.Foo死锁,线程将永远无法从死锁中恢复,如果这种情况发生得足够频繁,我们可能会耗尽资源。

是否有一种通用方法应该如何处理死锁的第三方代码?

ACancellationToken不起作用,因为第三方 api 不提供任何取消选项。

更新: 手头的方法来自SAP提供的SAPNCO.dll,用于建立和测试与sap系统的rfc连接,因此该方法不是简单的网络ping。我重命名了问题中的方法以避免进一步的误解

Pan*_*vos -1

您的代码不会取消被阻止的操作。使用 CancellationTokenSource 并将取消令牌传递给Task.Run

var cts=new CancellationTokenSource(timeout);

try
{
    await Task.Run(() => ThirdPartyCode.Ping(),cts.Token);
    return true;
}
catch(TaskCancelledException)
{
    return false;
}
Run Code Online (Sandbox Code Playgroud)

阻塞很可能是由于网络或 DNS 问题造成的,而不是实际的死锁。

这仍然浪费了等待网络操作完成的线程。您可以使用 .NET 自己的Ping.SendPingAsync异步 ping指定超时:

var ping=new Ping();

var reply=await ping.SendPingAsync(ip,timeout);
return reply.Status==IPStatus.Success;
Run Code Online (Sandbox Code Playgroud)

PingReply类包含比简单的成功/失败更详细的信息。Status属性单独区分路由问题、无法到达的目的地、超时等