gpt4 book ai didi

c# - 可以更新或删除的共享内存的线程安全枚举

转载 作者:行者123 更新时间:2023-12-03 13:17:50 28 4
gpt4 key购买 nike

我在线程之间有一个共享的对象,该对象用于保存文件状态信息。包含信息的对象是此类:

/// <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 [“key”];

可以在运行时修改字典。我在这里没问题。还是我错了?
在我看来,问题出在枚举器上,因为我想创建一个对集合进行迭代的枚举器。我该怎么做呢?我想到了以下三种解决方案:
  • 像这样制作一个枚举器:
    http://www.codeproject.com/Articles/56575/Thread-safe-enumeration-in-C
    (但使用ReaderWriterLockSlim)
  • 像SyncRoot一样公开锁对象(但使用
    ReaderWriterLockSlim),因此调用方将调用enter和exit读取方法。
  • 使用数据库(SQLite fx)来保存信息。

  • 1号的问题是:
  • 它使用构造函数进入条目读取模式。如果
    GetEnumerator()是手动调用的,不使用foreach吗?忘了
    调用处置。
  • 我不知道这是否是一种好的编码风格。即使我喜欢
    代码。
  • 如果调用者使用foreach,我不知道调用者可能会做什么
    在枚举器的实例化与调用之间进行处理。
    如果我了解我阅读的文档是正确的,则可以
    只要剩下一个读者在做,就最终阻止了作者
    一些繁重的工作。

  • 2号的问题是:
  • 我不喜欢公开此内容。我知道.NET API可以做到,但是
    不喜欢。
  • 由调用者决定是否正确进入和退出

  • 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个。

    最佳答案

    我会将您的问题视为要求反馈的信息,以帮助您学习。让我谈谈您已经确定的三种解决方案:

  • 是的,这就是为什么永远不要将这种设计作为API公开给第三方(甚至其他开发人员)的原因。正确使用是很棘手的。这篇代码项目文章有一些讨厌的建议。
  • 更好,因为此模型将在锁定方面是显式的,而不是隐式的。但是,我认为这违反了关注点分离。
  • 不确定您的意思。您的字典上可能有一个Snapshot()方法,该方法执行只读副本,可以安全地传递并读取它。这与解决方案1不同。

    完全有一个不同的解决方案:使用不可变的字典。即使在并发写访问下,也可以安全地传递,读取和枚举此类词典。此类字典/ map 通常使用树来实现。

    我将在一个关键点上详细说明:您需要考虑整个并发系统。您无法通过使所有组件都具有线程安全性(在您的情况下为字典)来确保您的应用正确无误。您需要定义字典的用途。

    你说:

    The reason why I want to iterate over the collection at runtime is that I want to find the values, that matches some criteria.



    您对数据进行了并发写入,并希望从字典中原子地获得一致的快照(也许要在UI中拍摄一些进度报告?)。现在我们知道了这个目标,我们可以设计一个解决方案:

    您可以在字典中添加一个Clone方法,该方法将在读取锁的同时克隆所有数据。这将为调用者提供一个新对象,然后可以独立枚举该对象。这将是一个干净且可安全暴露的API。

  • 关于c# - 可以更新或删除的共享内存的线程安全枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9854516/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com