.NET对共享登录会话的多线程访问

本文关键字:多线程 访问 会话 登录 共享 NET | 更新日期: 2023-09-27 18:25:18

我正在开发一个Web API应用程序,该应用程序通过API连接到后端系统。使用API的一个挑战是,它需要维护一个远程会话,该会话在API的所有线程/请求之间共享。会话每隔几个小时就会过期,需要通过登录进行"刷新"。

我当前实现的简化版本如下:

private static Object loginLock = new Object();
if(!Api.IsLoggedIn) 
{
    lock(loginLock)
    {
        if(!Api.IsLoggedIn)
        {
            Api.Login();
        }
    }
}
// Do stuff with the API

在高并发负载下,当需要登录时,线程会堆积在锁上,并在成功登录后一次通过一个线程,这会导致性能瓶颈。

我正在寻找的是一种在需要登录时阻止所有线程的方法,但在成功登录时让它们全部通过。

有没有更好的模式来解决这个问题?谷歌搜索似乎表明ReaderWriterLockSlimMonitor Wait/Pulse/PulseAll可能是比标准锁更好的候选者。

.NET对共享登录会话的多线程访问

这是一个不寻常的问题,我不知道内置了什么专门解决这个问题的东西。

记住,我在几分钟内就把它搞砸了,所以我绝对建议在很多人有机会看到它并指出它的缺陷之前不要使用它,这就是我的想法:

private Task _loginLock = null;
public void DoLoggedInCheck()
{
    if (!Api.IsLoggedIn)
    {
        var tcs = new TaskCompletionSource<int>();
        var tsk = tcs.Task;
        var result = Interlocked.CompareExchange(ref _loginLock, tsk, null);
        if (result == null)
        {
            if (!Api.IsLoggedIn)
            {
                Api.Login();
            }
            Interlocked.Exchange(ref _loginLock, null);
            tcs.SetResult(1);
        }
        else
        {
            result.Wait();
        }
    }
}

逻辑是,在发现需要登录的所有线程中,它们都(通过CompareExchange)竞争成为自愿解决问题的线程。其中一人获胜并完成任务,其余的人只是等待获胜者发出成功的信号。

这里仍然有少量的种族主义,但应该很少。

如果你想只使用工作线程来解决它,我看不到任何其他方法,有一个关键部分,这是关键部分的本质,一次只有一个线程可以通过它。完全另一种方法是将关键部分的处理委托给单独的线程。我不确定它是否会更高性能(很可能会慢得多),但一旦Api登录,就不会出现交通堵塞。

        private static AutoResetEvent requestLogin = new AutoResetEvent();
        private static ManualResetEvent responseLogin = new ManualResetEvent();
        //Worker thread:
        if(!Api.IsLoggedIn) 
        {
            requestLogin.Set();
            responseLogin.WaitOne();
        }
        //Login thread
        requestLogin.WaitOne();
        if(!Api.IsLoggedIn)
        {
            Api.Login();
        }
        responseLogin.Set();