在过去的 48 小时里,我一直在努力理解多线程 和Socket 编程。我尝试实现套接字编程并在不使用多线程时取得了成功。我对这两个主题都不熟悉,并且提出了 2-3 个关于堆栈本身的问题,需要同样的帮助。
经过大量谷歌搜索后,我发现了一个 article 解释了Socket Programming和Multithreading,但是我对这篇文章还是有很多疑惑,卡在了图5文章。
private void AcceptConnections()
{
while (true)
{
// Accept a connection
Socket socket = _serverSocket.Accept();
ConnectionInfo connection = new ConnectionInfo();
connection.Socket = socket;
// Create the thread for the receives.
connection.Thread = new Thread(ProcessConnection);
connection.Thread.IsBackground = true;
connection.Thread.Start(connection);
// Store the socket
lock (_connections) _connections.Add(connection);
}
}
在最后一行中,您可以看到一个锁已被占用,并且 delegate ProcessConnection 上方的 3-4 行已被绑定(bind)。
在这一点上,我不清楚这个锁是如何工作的。当锁被占用时,幕后发生了什么?为什么作者在这里使用锁?如果没有锁定会发生什么?线程 ProcessConnection 是如何工作的?什么事情同时发生?
我对所有这些问题感到困惑
我知道这里有一个问题列表,但如果你能帮助我理解使用多线程的方法,那将是一个很大的帮助。
请您参考如下方法:
connection.Thread.Start(connection) 通过调用 ProcessConnection 启动一个新线程,传递 connection 作为 state 参数。当前线程中的执行会立即继续下一行,而 ProcessConnection 会在新线程中执行。
ProcessConnection从AcceptConnections传递给它的ConnectionInfo对象中获取Socket对象,等待接收数据从 socket 。当它接收到数据时,它会遍历 connections 集合中的所有其他 ConnectionInfo 对象,并将此数据按顺序发送给它们中的每一个。
那么这里同时运行的是什么?嗯,我们有初始线程(称之为线程 0)在无限循环中执行 AcceptConnections。然后对于我们接受的每个套接字连接,我们都有一个线程执行 ProcessConnection。
需要锁是因为 ProcessConnection 使用 foreach 循环遍历已知连接以向它们发送数据。如果线程 0 在 foreach 中枚举集合时向集合添加新连接,则 InvalidOperationException 将在 ProcessConnection 中抛出.
lock 确实可以防止这种情况下的并发问题,但它也会导致潜在的性能问题。它不仅可以防止 AcceptConnections 在 ProcessConnection 枚举集合时修改集合。它还可以防止任何两个执行 ProcessConnection 的线程同时枚举集合。在这种情况下更好的选择是 ReaderWriterLockSlim这将允许多个线程同时读取集合。
