我需要在列表上加锁吗?C#

4
我用默认值填充了几个列表,将它们放入一个结构体中,然后将结构体传递给多个线程。每个线程都有不同的范围,因此线程1将访问list[0至199],线程2将访问[200-400]等。我需要锁吗?什么时候需要呢?我可以在不使用锁的情况下通过多个线程访问列表。但是,如果我的主线程想要读取列表中的数据(从不写入),那么我需要锁定吗?我确定我不需要,但在实施之前,我想询问一下。
-编辑-
谢谢大家,你们回答了我的问题。(只要没有人证明当前答案是错误的,我稍后会接受其中一个答案)
5个回答

8

如果你不修改集合,就根本不需要锁定。

如果你想要用其中一个线程修改集合,你可能需要查看ReaderWriterLock

Peter的评论很有意义。正如上面提到的MSDN链接,如果你使用的是.NET 3.5,应该考虑使用ReaderWriterLockSlim类。然而,这个想法是一样的。


2
或者使用新的和改进的 ReaderWriterLockSlim http://msdn.microsoft.com/zh-cn/library/system.threading.readerwriterlockslim.aspx - Peter Lillevold
1
请确保运行测试 -- 如果您没有持有锁足够长的时间来引起很多争用,那么标准锁实际上可能会更快。如果您几乎没有争用,那么 SpinLock(PFX/.NET 4.0中的新功能)在未来可能是更好的选择。 - Jonathan Rupp
@Jonathan,完全正确。在大规模并行平台上,自旋锁几乎总是表现更好。 - Mehrdad Afshari

3

如果您完全确定不会修改实际列表(添加项目、删除项目等),则不需要锁定。


2

如果您不写入内容,那么您就不需要锁。但是,如果您在其他线程中编写,则应该使用锁定。即使这些线程仅访问特定范围,如果您向列表中添加节点,则可能会出现问题。如果您不修改列表结构,而只更改节点中的内容,则我认为没有问题。


这不是真的。当你在读取它时,另一个线程可能会删除或修改你的集合。 - Chad Grant
我认为Megacan的意思是,如果线程只在列表中设置值,例如list[i] = value,并且对于不同的线程始终使用不同的索引,并且没有其他更改正在进行,则应该可以在没有锁的情况下保证线程安全。但是“应该”并不意味着它实际上是这样 - 我不了解List<>的内部情况,无法说它是否线程安全。我认为在这种情况下,应该使用数组 - 在这种情况下,数组是线程安全的。 - configurator
在当前实现下,大小不变的 List<T> 是线程安全的(它在内部是一个数组)。如果您更改了大小,则不是线程安全的(因为该数组可能需要重新分配以进行任何添加操作)。 - Jonathan Rupp
我应该指出,一个数组在这种情况下会更好。这样你就不需要依赖于List<T>的实现来内部使用数组。 - Jonathan Rupp
他在帖子中说,线程将访问列表的不同部分。我的答案已经考虑到了这一点。 - Megacan

1
在你的结构体对象中,我建议至少将变量标记为只读(ReadOnly),或者使用新的只读集合(ReadOnlyCollection)。
public struct MyStruct
{
    private readonly ReadOnlyCollection<int> _myInts;

    public MyStruct(ReadOnlyCollection<int> ints)
    {
        _myInts = ints;
    }
}

0

你有考虑过使用数组吗?只要你不在两个线程中访问相同的索引,数组是线程安全的。而且,如果不改变大小,它的速度会更快。


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