咨询区
Sebastian
在 .NET 框架中并没有线程安全的 ConcurrentHashSet
类,我想模仿 ConcurrentDictionary
来实现一个,目前写了一下桩代码。
public class ConcurrentHashSet<TElement> : ISet<TElement>
{
private readonly ConcurrentDictionary<TElement, object> _internal;
public ConcurrentHashSet(IEnumerable<TElement> elements = null)
{
_internal = new ConcurrentDictionary<TElement, object>();
if (elements != null)
UnionWith(elements);
}
public void UnionWith(IEnumerable<TElement> other)
{
if (other == null) throw new ArgumentNullException("other");
foreach (var otherElement in other)
Add(otherElement);
}
public bool Add(TElement item)
{
return _internal.TryAdd(item, null);
}
// I am not sure here if that fullfills contract correctly
void ICollection<TElement>.Add(TElement item)
{
Add(item);
}
public bool Contains(TElement item)
{
return _internal.ContainsKey(item);
}
public bool Remove(TElement item)
{
object ignore;
return _internal.TryRemove(item, out ignore);
}
public int Count
{
get { return _internal.Count; }
}
public IEnumerator<TElement> GetEnumerator()
{
return _internal.Keys.GetEnumerator();
}
}
我不确定这代码能否在 foreach 中还能保证原子性,请问是否有更好的实现?
回答区
Ben Mosher
我最近遇到了类似的场景,不过我更关注的更高性能的 Add,Contains,Remove
方法,下面是我的实现。
using System.Collections.Generic;
using System.Threading;
namespace BlahBlah.Utilities
{
public class ConcurrentHashSet<T> : IDisposable
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly HashSet<T> _hashSet = new HashSet<T>();
#region Implementation of ICollection<T> ...ish
public bool Add(T item)
{
try
{
_lock.EnterWriteLock();
return _hashSet.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public void Clear()
{
try
{
_lock.EnterWriteLock();
_hashSet.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
try
{
_lock.EnterReadLock();
return _hashSet.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
public bool Remove(T item)
{
try
{
_lock.EnterWriteLock();
return _hashSet.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public int Count
{
get
{
try
{
_lock.EnterReadLock();
return _hashSet.Count;
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
}
#endregion
#region Dispose
public void Dispose()
{
if (_lock != null) _lock.Dispose();
}
#endregion
}
}
点评区
实现一个 ConcurrentSet<T>
其实蛮有必要的,你在 github 或者其他第三方网站上会找到很多类似的 ConcurrentSet<T>
的实现,比如:https://pastebin.com/8REHRFFL