在.NET中不同线程之间共享列表

3

我有一个静态列表,将被不同的线程访问,每个线程都会向列表中添加、读取和删除自己独特的项目。我想知道是否需要担心使这个变量线程安全,因为即使相同的列表对象在线程之间共享,它们也只修改自己独特的项目。


只有在动态添加它们时才返回已翻译的文本。 - kenny
他谈论到“删除”、“添加”,我认为这是默认的动态操作,或者它们没有意义。 - Nick Martyshchenko
这是一个 WCF 服务,将由几个客户端调用。每个客户端通过向列表中添加其详细信息来向服务注册自己。由于客户端和服务之间的交互时间较长(6 小时至 1 天),存在网络连接断开等情况的可能性。因此,在这些情况下,客户端可以重新创建新会话并从读取此列表中获取旧会话的状态。这就是使用静态列表的原因。 - john
4个回答

10

您一定要通过 lockReaderWriterLockSlim 等方式来实现线程安全访问。

如果您在第一次分配(通过 new)后没有修改 List<> 变量本身,则它是线程安全的,但需要对元素访问进行线程安全控制(因为您说您正在添加/删除列表中的元素,因此更改了其状态)。

顺便说一句,如果线程修改自己的项目,为什么您要共享它们?那么您实现了什么?为什么要这样组织?如果您展示细节,可能会有更好的建议。


+1 特别注意到提及删除/添加项目,这意味着整个列表的状态正在发生变化。 - Andrew Barber
@john:为什么服务细节不仅局限于处理对象/线程?全局可访问的列表似乎是不必要的。 - Vlad
@Vlad,我们希望客户端注册信息仍然可用,即使会话结束,比如由于网络故障,这就是为什么它不与本地变量绑定的原因。 - john
1
@john:好的。那么,对列表的任何修改(插入/删除)都必须受到锁的保护。如果您可以保证每个单独的值都是由专用线程添加/删除/处理的,则不需要在修改时进行锁定(仅在向列表中插入/删除时)。 - Vlad
@Vlad,感谢你在我离线期间的关心 :) @john,你可能最好使用ConcurrentDictionary(TKey,TValue)http://bit.ly/c2tigi来完成你的任务,因为你需要在List中查找客户端数据。这样,您将避免任何锁定,并获得在查找值时的巨大性能奖励。ConcurrentDictionary也适用于.NET 3.5到Rx。 - Nick Martyshchenko
显示剩余2条评论

2

只有在更改列表(添加/删除)时才需要担心。但是,如果您正在使用刚获取/添加的对象,则不需要担心(除非它需要在多个线程上使用)。

static List<ClientState> _clientStates;
static readonly Object _clientStatesLock = new Object();


/// Gets the state of a client for a given Id.
/// Returns null if no state exists.
/// This method is threadsafe.
ClientState GetState (ClientIdentifier id){

    lock (_clientStatesLock)
        return  _clientStates.FirstOrDefault (cs => cs.Id == id);
}

同样适用于添加/删除项目。

2
如果您的线程没有以任何方式共享数据,那么为什么要让它们竞争访问同一个列表。这可能是 线程本地存储模式 的可接受用法。.NET 提供了以下机制。
  • Thread.SetDataThread.GetData
  • ThreadStaticAttribute
或者,如果您可以将线程抽象成自己的自定义类的单独实例,然后使用实例变量而不是静态列表变量。

1

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