我在线程之间有一个共享对象,用于保存文件状态信息。保存信息的对象是这个类:
/// <summary>
/// A synchronized dictionary class.
/// Uses ReaderWriterLockSlim to handle locking. The dictionary does not allow recursion by enumeration. It is purly used for quick read access.
/// </summary>
/// <typeparam name="T">Type that is going to be kept.</typeparam>
public sealed class SynchronizedDictionary<U,T> : IEnumerable<T>
{
private System.Threading.ReaderWriterLockSlim _lock = new System.Threading.ReaderWriterLockSlim();
private Dictionary<U, T> _collection = null;
public SynchronizedDictionary()
{
_collection = new Dictionary<U, T>();
}
/// <summary>
/// if getting:
/// Enters read lock.
/// Tries to get the value.
///
/// if setting:
/// Enters write lock.
/// Tries to set value.
/// </summary>
/// <param name="key">The key to fetch the value with.</param>
/// <returns>Object of T</returns>
public T this[U key]
{
get
{
_lock.EnterReadLock();
try
{
return _collection[key];
}
finally
{
_lock.ExitReadLock();
}
}
set
{
Add(key, value);
}
}
/// <summary>
/// Enters write lock.
/// Removes key from collection
/// </summary>
/// <param name="key">Key to remove.</param>
public void Remove(U key)
{
_lock.EnterWriteLock();
try
{
_collection.Remove(key);
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// Enters write lock.
/// Adds value to the collection if key does not exists.
/// </summary>
/// <param name="key">Key to add.</param>
/// <param name="value">Value to add.</param>
private void Add(U key, T value)
{
_lock.EnterWriteLock();
if (!_collection.ContainsKey(key))
{
try
{
_collection[key] = value;
}
finally
{
_lock.ExitWriteLock();
}
}
}
/// <summary>
/// Collection does not support iteration.
/// </summary>
/// <returns>Throw NotSupportedException</returns>
public IEnumerator<T> GetEnumerator()
{
throw new NotSupportedException();
}
/// <summary>
/// Collection does not support iteration.
/// </summary>
/// <returns>Throw NotSupportedException</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotSupportedException();
}
}
我把这个词典称为: SynchronizedDictionary _cache = new SynchronizedDictionary();
可以生成其他线程并使用这样的线程: _cache [ “键”];
可以在运行时修改字典。我觉得这里没问题。还是我错了? 在我看来,问题在于枚举器,因为我想创建一个迭代集合的枚举器。我该怎么做呢?我想到了这三个解决方案:
数字1的问题是:
数字2的问题是:
没有问题3)我的眼睛。但我正在做这个小项目作为业余时间项目,我想了解更多有关多线程和反射的知识,所以我想把它作为最后一个选项。 我想在运行时迭代集合的原因是我想找到符合某些条件的值。
也许只是我发明了一个问题?
我知道ConcurrentDictionary,但我不想使用它。我正在使用这个项目作为游乐场。玩线程和反射。
修改
我被问到我在读书和写作是什么。我将在此编辑中告诉它。我正在读这堂课:
public class AssemblyInformation
{
public string FilePath { get; private set; }
public string Name { get; private set; }
public AssemblyInformation(string filePath, string name)
{
FilePath = filePath;
Name = name;
}
}
我正在进行大量读取,并且几乎没有在运行时写入。也许我会做2000和1写。也不会有很多对象,也许是200。
答案 0 :(得分:2)
我会将您的问题视为反馈请求,以帮助您学习。让我谈谈你已经确定的三个解决方案:
完全有另一种解决方案:使用不可变字典。即使在并发写访问下,这样的字典也可以安全地传递,读取和枚举。这些词典/地图通常使用树来实现。
我将详细阐述一个关键点:您需要考虑整个并发系统。通过使所有组件都是线程安全的(在您的情况下是字典),您无法使应用程序正确。您需要定义,使用字典 for 。
你说:
我想在运行时迭代集合的原因是 我希望找到符合某些标准的值。
您是否发生了对数据的并发写入,并希望从字典中原子地获取一致的快照(可能在UI中拍摄一些进度报告?)。现在我们知道了这个目标,我们可以设计一个解决方案:
您可以在字典中添加克隆方法,该方法在读取锁定时克隆所有数据。这将为调用者提供一个新的对象,然后可以单独枚举。这将是一个干净且安全的可曝光API。
答案 1 :(得分:1)
我没有直接实施IEnumerable
,而是添加Values
属性(例如Dictionary.Values
):
public IEnumerable<T> Values {
get {
_lock.EnterReadLock();
try {
foreach (T v in _collection.Values) {
yield return v;
}
} finally {
_lock.ExitReadLock();
}
}
}