あなたの実装は正しいです。.NET Frameworkには、残念ながら、組み込みの同時ハッシュセットタイプはありません。ただし、いくつかの回避策があります。
ConcurrentDictionary(推奨)
これConcurrentDictionary<TKey, TValue>
は、名前空間でクラスを使用することSystem.Collections.Concurrent
です。この場合、値は無意味なので、単純なbyte
(メモリ内の1バイト)を使用できます。
private ConcurrentDictionary<string, byte> _data;
タイプはスレッドセーフであり、HashSet<T>
キーと値が異なるオブジェクトであることを除いて同じ利点が得られるため、これは推奨されるオプションです。
ソース:ソーシャルMSDN
ConcurrentBag
重複するエントリを気にしない場合ConcurrentBag<T>
は、前のクラスと同じ名前空間のクラスを使用できます。
private ConcurrentBag<string> _data;
自己実装
最後に、そうしたように、.NETがスレッドセーフになるように提供するロックまたはその他の方法を使用して、独自のデータ型を実装できます。これが良い例です:.NetにConcurrentHashSetを実装する方法
このソリューションの唯一の欠点はHashSet<T>
、読み取り操作であっても、型が公式に同時アクセスできないことです。
リンクされた投稿のコードを引用します(元々はBen Mosherによって書かれました)。
using System;
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)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public void Clear()
{
_lock.EnterWriteLock();
try
{
_hashSet.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return _hashSet.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
public bool Remove(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public int Count
{
get
{
_lock.EnterReadLock();
try
{
return _hashSet.Count;
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
}
#endregion
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_lock != null)
_lock.Dispose();
}
~ConcurrentHashSet()
{
Dispose(false);
}
#endregion
}
}
編集:try
例外をスローし、finally
ブロックに含まれる命令を実行する可能性があるため、ブロックの外にある入り口ロックメソッドを移動します。
System.Collections.Concurrent