Locking on an interned string?

前端 未结 6 1280
栀梦
栀梦 2021-01-01 16:43

Update: It is acceptable if this method is not thread safe, but I\'m interested in learning how I would make it thread safe. Also, I do not want to lock on

6条回答
  •  青春惊慌失措
    2021-01-01 17:29

    A variant of Daniel's answer...

    Rather than creating a new lock object for every single string you could share a small-ish set of locks, choosing which lock to use depending on the string's hashcode. This will mean less GC pressure if you potentially have thousands, or millions, of keys, and should allow enough granularity to avoid any serious blocking (perhaps after a few tweaks, if necessary).

    public static T CheckCache(string key, Func fn, DateTime expires)
    {
        object cached = HttpContext.Current.Cache[key];
        if (cached != null)
            return (T)cached;
    
        int stripeIndex = (key.GetHashCode() & 0x7FFFFFFF) % _stripes.Length;
    
        lock (_stripes[stripeIndex])
        {
            T result = fn();
            HttpContext.Current.Cache.Insert(key, result, null, expires,
                                             Cache.NoSlidingExpiration);
            return result;
        }
    }
    
    // share a set of 32 locks
    private static readonly object[] _stripes = Enumerable.Range(0, 32)
                                                          .Select(x => new object())
                                                          .ToArray();
    

    This will allow you to tweak the locking granularity to suit your particular needs just by changing the number of elements in the _stripes array. (However, if you need close to one-lock-per-string granularity then you're better off going with Daniel's answer.)

提交回复
热议问题