c# - 仅当线程处于某个方法时才锁定多个方法

标签 c# .net multithreading locking

我有一个类(简化示例):

public class SomeCollection : ICloneable
{
    public void Add(Item item) { /* ... */ }
    public void Remove(Item item) { /* ... */ }
    public Item Get(Key key) { /* ... */ }
    /*
    ...
    */
    public object Clone() { /* ... */ }
}

我需要当一个线程进入 Clone() 时,其他线程不能进入 Add 或 Remove,但可以进入 Get。起初我想到了:

    public void Add(Item item) { lock(addLock) { /* ... */ } }
    public void Remove(Item item) { lock(removeLock) { /* ... */ } }

    public object Clone(Item item)
    { 
        lock(addLock)
        {
            lock(removeLock)
            {
                /* ... */
            }
        }
    }

这可行(我认为)但有一些缺点: * 我不希望两个线程进入 Add 相互阻塞——我正在处理更深层次的代码 * 我将不得不承受每次调用 Add 或 Remove 的锁定开销

然后我想到了这个

    private volatile bool cloning = false; // notice the volatile keyword

    public void Add(Item item)
    {
         int i = 0;
         while(cloning)
         { 
             if (i++ > 20)
                 throw new TimeoutException();
             Thread.Sleep(50); // waits 50 milliseconds
         }
         /* ... */
    } // and the same for Remove

    public object Clone()
    {
        cloning = true;
        try
        {
            /* do the cloning */
        } finally { cloning = false; }
    }

但是这种方法:

  • 更复杂
  • Clone 可以在一个线程还没有执行完 Add 或 Remove 时进入
  • 看起来不自然

我给了ReadWriterLockSlim看一眼,但似乎不适合我的场景。

我需要这个,因为 Clone 方法需要很长时间(可能需要一秒钟 - 集合是巨大的)并且在这段时间内进行更改会破坏枚举器(在 foreach 循环中使用)。是的,我必须使用 foreach,因为底层 key 集合除了 IEnumerable 外不公开任何其他内容。

会推荐什么?

最佳答案

您能否详细解释一下为什么 ReaderWriterLockSlim 不适合您的场景?

当然,您不会因为它的经典用法而使用它,但将 Clone 方法视为您的编写者,将添加/删除方法视为您的读者,我认为它很合适。

[edit] 另一件事:如果你走这条路,请确保记录你为什么“向后”使用 ReaderWriterLockSlim,以便下一个阅读代码的人(或六个月后的你)理解发生了什么。

关于c# - 仅当线程处于某个方法时才锁定多个方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1014130/

相关文章:

c# - Access 是否仅限于连接数据库并运行查询的用户数量?

c# - 以 MDI 形式多次防止同一个子窗口

c# - 如何在非事件窗口中用代码模拟键盘事件?

java - 当另一个线程通知线程时,该线程从哪里开始执行?

java - 使用多线程进行硬币翻转

c# - 为什么没有标记为 Serializable 的类不能使用 BinaryFormatter 序列化?

c# - ASPNETCOMPILER(0,0) : Error ASPRUNTIME: Object reference not set to an instance of an object

c# - 在 .NET 应用程序中隐藏 SMTP 密码

.net - 样式 TargetType 属性问题

c++ - 为什么这段代码中调用了两次析构函数?