我有一个List和两个使用List的线程。
第一个线程是获取新连接,每个新连接都添加到List。
第二个线程循环遍历List以处理连接(使用foreach)。
问题在于,有时当第二个线程在List上循环时,List会在循环结束之前更改。我甚至尝试创建列表的新副本并循环遍历它。但它会产生一些其他问题。
我不想创建一个新线程来处理每个新连接,因为我知道太多线程会影响性能。有没有其他方法来处理连接?
答案 0 :(得分:3)
2个问题。
1)您需要锁定列表。 您需要确保您对列表具有互斥访问权限,因此在修改时无法对其进行枚举。 第一种解决方案是使用锁:
class Mailbox {
List<int> list;
void Send(int a) {
lock(list) {
list.Add(a);
}
}
int Receive() {
lock(list) {
// Enumerate
return ...;
}
}
}
更优雅的是,您可以使用Concurrent命名空间中的一个新集合,例如BlockingCollection。后者不是枚举安全的,但是提供了一个Take()
方法,可以用来从中检索对象,而生产者插入它们。
2)避免创建大量的线程。 您可以使用.NET thread pool将任意数量的请求排入队列,框架将负责将它们映射到实际线程,而不会杀死系统。
答案 1 :(得分:1)
最简单的解决方案是在每个帖子的列表中使用lock
。
第一个帖子:
lock(yourList)
{
yourList.Add(...);
}
第二个帖子:
lock(yourList)
{
foreach(var item in yourList)
{
...
}
}
这将阻止第一个线程在第二个线程处于迭代过程中时添加连接。如果第二个线程正在遍历列表并且第一个线程尝试输入代码的lock
- ed部分,它将等到第二个线程完成循环遍历列表。
答案 2 :(得分:1)
正如其他人所写,你需要使用锁来管理这两个线程的并发性。
就避免多线程而言,我认为这在很大程度上取决于我们谈论的线程数量。如果您只使用了几个套接字连接,那么也许可以在自己的线程中从每个连接读取同步读取。但是,如果你正在讨论很多套接字连接,那么我就不会为每个连接使用专用线程。
到目前为止,从多个套接字读取的最有效方法是使用异步读取(Socket.BeginReceive())。在引擎盖下,这些异步方法使用I/O Completion Ports,效率很高。使用异步套接字方法实现可以处理数千个并发连接的自定义TCP服务器相对容易。
答案 3 :(得分:-4)
我对此并不太了解,但我想到的第一个想法是:
存储列表的长度并循环播放
while (var i < lengthoflist)
{
//whatever fancy stuff your code does
i++;
}
但我对套接字一无所知,这只是我想到的一个通用的想法,所以我不知道这是否会奏效。