ASP.NET Core Web API 应用程序是不是可能出现死锁或应用程序挂起状态

Posted

技术标签:

【中文标题】ASP.NET Core Web API 应用程序是不是可能出现死锁或应用程序挂起状态【英文标题】:Is deadlock or application hung state possible for ASP.NET Core Web API applicationASP.NET Core Web API 应用程序是否可能出现死锁或应用程序挂起状态 【发布时间】:2022-01-13 04:10:59 【问题描述】:

我有一个 ASP.NET Core 3.1 Web API 应用程序,它有一个后台主机服务,我在其中编写了以下代码来模拟应用程序的死锁:

public class Worker : IHostedService

    public Task StartAsync(CancellationToken cancellationToken)
    
        var a = new object();
        var b = new object();

        lock (a)
        
            lock (b)
            
            
        

        // other thread
        lock (b)
        
            lock (a)
            
            
        

        return Task.CompletedTask;
    

应用程序正在运行,但应用程序不会死锁或挂起状态,我仍然可以访问 web api 端点并且结果返回给我。

是否有可能使正在运行的 Web 应用程序进入死锁或挂起状态,以便 API 的 NONE 给出任何 200 结果?

谢谢。

【问题讨论】:

只需添加一个测试,它会产生多个线程,比如 100 并运行 10 分钟,你就会知道答案 以其当前形式我会说不,除非你有从不同线程多次调用 StartAsync 的东西......,看到我看到 IHostedService,我猜这是从 1 个线程调用的只有..所以你永远不会有竞争线程.. 答案很简单 Is deadlock or application hung state possible for ASP.NET Core Web API application YES 因为你的意思的范围不够具体,以至于它永远不会,因为它只是语言的一个特征/用法。我认为您应该更改标题,“对于此代码”,如果由多个线程调用,答案是肯定的。 @Seabizkit,感谢您的回复。能否请您提供一些示例代码? @user584018 我已经说明了一些事情,1 这不是从网络请求中调用的吗?那么为什么这是问题的一部分,2你正常启动 IHostedService 的方式是在 1 个线程上,所以没有迹象表明它是如何从多个线程调用的。 3 它的表述方式确实构成了一个 gd 问题……也就是说,我是否有可能跳 3 次。 4 可以编写一个测试,但我们离开了 IHostedServic。就像操作的真正问题一样,是什么让您认为这是由多个线程调用的?别管实际的问题。 【参考方案1】:

正如所写,当前方法将从不死锁。

锁对象是方法的本地对象。正确的锁定必须使用方法范围之外的对象。

在接下来的版本中,锁定对象对于类来说是静态的,并且锁定会增加一个微小的延迟来模拟正在执行的工作。在这种情况下,应用会在方法的第二个入口处死锁。

public class Worker

    private static readonly object _a = new();
    private static readonly object _b = new();
    private const int _delay = 5;

    public Task StartAsync2( int n )
    
        lock( _a )
        
            Console.WriteLine( $"n: _a1 enter" );
            lock( _b )
            
                Console.WriteLine( $"n: _b1 enter" );
                Thread.Sleep( _delay );
            
            Console.WriteLine( $"n: _b1 exit" );
        
        Console.WriteLine( $"n: _a1 exit" );

        // other thread
        lock( _b )
        
            Console.WriteLine( $"n: _b2 enter" );
            lock( _a )
            
                Console.WriteLine( $"n: _a2 enter" );
                Thread.Sleep( _delay );
            
            Console.WriteLine( $"n: _a2 exit" );
        
        Console.WriteLine( $"n: _b2 exit" );

        return Task.CompletedTask;
    

下面是如何执行Worker导致死锁:

var w = new Worker();
var t = new Task[5];

for( int i = 0; i < t.Length; i++ )

    int n = i;
    t[i] = Task.Run( () =>
    
        Console.WriteLine( $"n start" );
        w.StartAsync2( n );
        Console.WriteLine( $"n end" );

        return Task.CompletedTask;
     );


Task.WaitAll( t );

【讨论】:

谢谢!!!我试图在 asp.net web api 控制器端点中调用Worker,它永远不会返回响应,这意味着它是死锁,但这不会使整个应用程序死锁,我仍然可以调用另一个 api 端点。想法? 我也尝试加入后台服务,但整个应用程序没有陷入死锁或挂起的情况,API 端点仍然响应并给出 200 :( 您需要将Worker 添加到所有请求都经过的中间件管道中。当每个请求通过时,Worker 必须被调用,最终有足够的活动,应用程序将耗尽资源。【参考方案2】:

不确定 ASP.NET,根据您的代码示例,您可以尝试使用 Thread sleep / delay 之类的东西,这样每个线程就不会太快锁定资源。

大概是这样的:

        lock (a)
        
            Thread.sleep(..duration..)

            lock (b)
            
            
        

        // other thread
        lock (b)
        
            Thread.sleep(..duration..)

            lock (a)
            
            
        

【讨论】:

对我来说看起来像代码味道,迫使这样的暂停。 是的,但因为它只是为了模拟,我认为没关系

以上是关于ASP.NET Core Web API 应用程序是不是可能出现死锁或应用程序挂起状态的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core Web API

Asp.net core 3.1 保护 API 和 Web 应用程序

ASP.NET Core Web API 身份验证

Asp.Net Core Web API 应用程序:如何更改监听地址?

Xamarin Mobile 使用的 ASP.Net Core Web API

处理 ASP.NET Core Web API 对象属性绑定