C#:不管这种方法是线程安全的

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

我有一个服务类,这并请求一些外部的服务。外部服务需要的sessionId,这的sessionId活的时间是未知的(可以是几秒钟,可以是几分钟,可以是数小时,可天。可以是1个请求,可以1000项请求,没有人知道这一点。我们不能链接到它在所有)。

我创建了一个方法,该方法得到的sessionId:

    private async Task<string> LoginAsync()
    {
        using (HttpClient clientLogin = new HttpClient())
        {
            //....
        }
        return sessionId;
    }

我宣布我的类中的以下变量

public class BillComService : IBillComService
{
    private static Lazy<string> SessionId;

并且初始化它的构造函数:

    public BillComService()
    {
        if (SessionId == null)
            SessionId = new Lazy<string>(() => LoginAsync().Result);
        //....
    }

然后我用它在我里面的方法:

    private async Task<T> Read<T>(string id, string endpoint)
    {
        var nvc = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("devKey", devKey),
                new KeyValuePair<string, string>("sessionId", SessionId.Value)
            };

OK,它的罚款。想想的sessionId已过期。与投BillComInvalidSessionException方法

现在我写了下面的方法,如果会话id过期调用LoginAsync方法后重复我的要求。常用的方法:

    private async Task<T> Retry<T>(Func<Task<T>> func)
    {
        try
        {
            return await func();
        }
        catch (BillComInvalidSessionException)
        {
            SessionId = new Lazy<string>(() => LoginAsync().Result);
            return await Retry(func);
        }
    }

Read

    private async Task<T> ReadWithRetry<T>(string id, string endpoint)
    {
        return await Retry(async () => await Read<T>(id, endpoint));
    }

所以,我的公开方法是:

    public async Task<Customer> GetCustomerAsync(string id)
    {
        return await ReadWithRetry<Customer>(id, "Crud/Read/Customer.json");
    }

它的工作原理和做工精细。但我不知道,无论是线程安全的:)

c# multithreading design-patterns thread-safety
2个回答
1
投票

您的代码不执行任何种类的同步,并允许并行发布的一个或多个登录。这是否是一个问题或不完全依赖于远程执行发出会话ID。

这是我能想到的3种主要方案:

  1. 远程登录过程中,每个开发的关键同步会话ID生成,并保证返回相同的会话ID的并发登录。
  2. 远程登录过程中会发出每一个登录新的会话ID,即使在争用情况,但所有的会话ID将仍然有效。
  3. 远程登录过程中会发出每一个登录新的会话ID,但以后每次登录均无效对于给定的开发者的关键先前发出的会话ID。

与场景1和2,可能发生最坏的是低效率(例如不必要的网络IO)由于并发登录进程。

然而,方案3,那么事情可能因为你可能最终与很多重试循环,因为会话ID可以被正确发出后得到无效变得丑陋。越多的并发请求有一个无效的会话,它会得到最糟糕的。

如果你想确保你的代码是独立于远程执行的安全,那么你就必须同步SessionId读取和写入,其中包括同步登录过程也是如此。尽管如此,远程实现的行为是他们的服务合同的一部分,所以它也可以是合理的为你实现把这种行为纳入考虑。


2
投票

不,这不是线程安全的。

你有一个比赛,当多个线程并行设置共享SessionId场和另一个当一个线程被设置SessionId而其他线程正在使用它。

BTW:看来你是缺少一个等待调用LoginAsync时()。

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