Alternative to ConcurrentDictionary for portable c

2019-03-25 18:28发布

I'm writing a portable class library that targets .NET 4.5, Windows Store apps and Windows Phone 8. I need an efficient in-memory cache mechanism, so I was thinking about using ConcurrentDictionary<K,V>, but it's not available in WP8.

There will be many reads and relatively few writes, so ideally I'd like a collection that supports lock-free reads from multiple threads, and write by a single thread. The non-generic Hashtable has that property, according to MSDN, but unfortunately it's not available in the PCL...

Is there another collection class available in the PCL that matches this requirement? If not, what would be a good way to achieve thread safety without locking for reads? (locking for writes is OK, since it won't happen too often)


EDIT: thanks to JaredPar's guidance, I eventually implemented my cache in a completely lock-free fashion, using ImmutableDictionary<TKey, TValue> from Microsoft.Bcl.Immutable:

class Cache<TKey, TValue>
{
    private IImmutableDictionary<TKey, TValue> _cache = ImmutableDictionary.Create<TKey, TValue>();

    public TValue GetOrAdd(TKey key, [NotNull] Func<TKey, TValue> valueFactory)
    {
        valueFactory.CheckArgumentNull("valueFactory");

        TValue newValue = default(TValue);
        bool newValueCreated = false;
        while (true)
        {
            var oldCache = _cache;
            TValue value;
            if (oldCache.TryGetValue(key, out value))
                return value;

            // Value not found; create it if necessary
            if (!newValueCreated)
            {
                newValue = valueFactory(key);
                newValueCreated = true;
            }

            // Add the new value to the cache
            var newCache = oldCache.Add(key, newValue);
            if (Interlocked.CompareExchange(ref _cache, newCache, oldCache) == oldCache)
            {
                // Cache successfully written
                return newValue;
            }

            // Failed to write the new cache because another thread
            // already changed it; try again.
        }
    }

    public void Clear()
    {
        _cache = _cache.Clear();
    }
}

1条回答
贼婆χ
2楼-- · 2019-03-25 18:46

One option to consider is to write a thin facade over an immutable search tree. There are several immutable search trees available on the web to choose from. I usually base mine off of Eric Lipperts great post on the subject

Using this as the backing data structure will give you lock free. Writes to the tree can be done in a lock free fashion with CAS as well. This will be a bit slower than ConcurrentDictionary because lookups are O(Log(N)) instead of approaching O(1). But it should do the trick for you

查看更多
登录 后发表回答