并发集合枚举器

7

我正在编写自己的优先队列/排序列表实现,并希望它具有并发性。 为了使它线程安全,我使用 lock(someObject) ,我想验证 C# 中互斥锁的一些行为。

我的排序列表的内部表示基本上是一个链接在一起的带有 head 和插槽的链表。 类似于:

internal class Slot
{
    internal T Value;
    internal Slot Next;

    public Slot(T value, Slot next = null)
    {
        Value = value;
        Next = next;
    }
}

每次我在操作head时,由于线程安全性,我都需要使用lock(someObject)。为了实现ICollection接口,我必须实现public IEnumerator<T> GetEnumerator()方法。在这个方法中,我需要使用互斥锁来读取我的head

public IEnumerator<T> GetEnumerator()
{
    lock (syncLock)
    {
        var curr = head;
        while (curr != null)
        {
            yield return curr.Value;
            curr = curr.Next;
        }
    }
}

我的问题是:在枚举器中,syncLock 是否在整个时间内都被锁定(因此在到达方法结尾后将被解锁),还是在产生值后自动解锁?


7
在整个枚举过程中,它将被锁定 - 因此,这是一个非常糟糕的想法。 - Matthew Watson
1
你能利用 System.Collections.Concurrent 中的任何集合,例如 BlockingCollection 吗?https://msdn.microsoft.com/zh-cn/library/system.collections.concurrent.aspx - Leo
说实话,像这样将优先队列“并发”化并不是一个很好的想法。只需让它非线程安全,并让其用户决定何时以及如何锁定,如果它被多个线程使用。但如果您坚持要这样做-获取锁,创建所有项的副本,释放锁,然后将该副本返回给GetEnumerator的调用者。 - Evk
需要能够返回一个枚举器吗?你如何使用它? - Manfred Radlwimmer
@ManfredRadlwimmer,因为它应该实现“ICollection”接口,从而实现“public IEnumerator<T> GetEnumerator()”。 - Lukas Forst
显示剩余9条评论
1个回答

1

感谢评论中的各位,以下是总结:

答案:是的,syncLock会被锁定整个时间 → 因此,这是一个非常糟糕的想法

可能的解决方案:

  • 使集合不具有线程安全性
  • 获取锁定,复制整个集合并返回该集合的枚举器 @Evk
  • 使用某种布尔标志,在枚举集合时将其设置为true,并在调用AddClearRemove方法时抛出异常 -> 这是默认的List行为 @ManfredRadlwimmer
  • 使该集合不可变 @InBetween

你还有另一种方法可以考虑:创建一个不可变的集合。 - InBetween

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接