0

Consider a following pseudo code:

    private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    private static Token CachedToken = new Token();

    public async Task DoWorkAsync()
    {
        var token = CachedToken;

        if (!token.IsInvalid) { //new Token() is invalid
            var response = await _apiClient.MakeRequest(token);
            if (response.StatusCode != HttpStatusCode.Unauthorized) {
                return response;
            }
        }

        await _semaphore.WaitAsync();
        try {
            if (CachedToken.AccessToken == token.AccessToken) {
                CachedToken = await GetFreshToken();
            }
            token = CachedToken;
        }
        finally {
            _semaphore.Release();
        }

        return await _apiClient.MakeRequest(token);
    }

So my question is how to unlock all threads waiting for semaphore as soon as first thread has updated the cache and got released?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Grigoryants Artem
  • 1,401
  • 2
  • 15
  • 32
  • 2
    The duplicate covers how to do what you asked for, but I'd suggest not doing that anyway. Verifying that the cached value is valid is a very quick an easy check, so it seems unlikely it'd be a performance problem to serialize them, and it'd be a lot safer to ensure that it's a proper critical section that really does only ever have one thread running at a time. – Servy Jul 29 '21 at 19:03
  • 1
    If appears you are trying to reinvent the wheel by writing your own caching system. Far better to use any of the myriad (well maybe 2 or 3) cache packages already out there. – Neil Jul 29 '21 at 19:06
  • 1
    As a side note please be aware that the non-readonly and non-volatile `CachedToken` field is accessed without synchronization in this line: `var token = CachedToken;`. I would suggest to ensure that the field is accessed with `volatile` semantics: `var token = Volatile.Read(ref CachedToken);`. Also make sure that the `IsInvalid` property is thread-safe, because it is invoked on a non synchronized context. – Theodor Zoulias Jul 29 '21 at 21:19
  • Also [this](https://stackoverflow.com/questions/68467426/enforce-an-async-method-to-be-called-lazily-on-demand-and-called-again-when-the "Enforce an async method to be called lazily on demand, and called again when the previous result has expired") question might be slightly relevant to the general problem you are trying to solve. – Theodor Zoulias Jul 29 '21 at 21:24

0 Answers0