2010-06-29 44 views
1

过去48小时,我一直试图了解MultithreadingSocket Programming。我试图实现套接字编程,并在不使用多线程时取得了成功。我对这两个主题都很陌生,并且在堆栈本身提出了2-3个问题,需要相同的帮助。如何使用多线程,锁,套接字编程

google搜索了很多后,我发现了一个article解释Socket ProgrammingMultithreading,但还是有很多疑惑的这篇文章中,并在文章中被困在Figure 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); 
     } 
    } 

在最后一行,你可以看到一个lock已经采取和3-4线delegate ProcessConnection上面的约束。

在这一点上,我不清楚这个锁是如何工作的。锁已经发生在幕后的事情是什么?为什么作者在这里使用锁定?如果没有锁定,会发生什么?线程ProcessConnection如何工作?什么事情同时发生?

我弄糊涂了所有这些问题

我知道有一个问题清单在这里,但是这将是一个很大的帮助,如果你能帮助我了解多线程工作的方法。

回答

2

connection.Thread.Start(connection)启动一个新线程来ProcessConnection通话,传递connectionstate参数。当前线程中的执行会立即继续执行下一行,而在新线程中执行ProcessConnection

ProcessConnection从传递给它的ConnectionInfo对象中获取Socket对象AcceptConnections并等待从套接字接收数据。当它接收到数据时,它循环访问connections集合中的所有其他ConnectionInfo对象,并将这些数据按顺序发送给它们中的每一个。

那么这里同时运行什么?那么,我们有最初的线程(称为线程0)在无限循环中执行AcceptConnections。然后对于我们接受的每个套接字连接,我们有一个执行ProcessConnection的线程。

锁是需要的,因为ProcessConnection使用foreach循环通过已知的连接发送它们的数据。如果线程0在集合正在枚举foreach时向该集合添加新连接,则将在ProcessConnection中抛出InvalidOperationException

lock在这种情况下确实避免了并发问题,但它也会导致潜在的性能问题。它不仅防止AcceptConnections修改集合,而ProcessConnection正在枚举它。它还可以防止执行ProcessConnection的任何两个线程同时枚举集合。在这种情况下更好的选择是ReaderWriterLockSlim,这将允许多个线程同时读取集合。

+0

'锁(_connections) { 的foreach(ConnectionInfo康恩在_connections) { 如果(参数conn =连接!) { conn.Socket.Send( 缓冲器,bytesRead,SocketFlags.None); } } }'这已用于向每个套接字广播相同的消息?正如您在第二段 – 2010-06-29 13:57:05

+0

中解释的那样,很好的解释,在这里明确所有要点。仍然阅读您的答案,并将文章作为参考。当我完全阅读时会回复给你。 – 2010-06-29 13:59:19

+0

@Shantanu:是的,那个foreach循环是将收到的消息广播到其他每个套接字的环。 – 2010-06-29 14:08:23

1

我假设_connectionsList<ConnectionInfo>:列表不是线程安全的,并且此线程将项目添加到该列表。如果另一个线程将同时移除一个项目,结果将是不可预测的。所以你必须确保没有其他进程可以使用锁来访问它。

connection.Thread.Start(connection);启动一个新的线程,该线程将立即启动或即将启动。当前线程(您在这里看到的代码)将无法控制它。这个新线程提供了一个ConnectionInfo对象,所以它会知道在哪个套接字上执行任务。在当前线程不断收听新客户端时,ProcessConnection函数将处理最近接受的客户端。

+0

很好地解释和thx为您宝贵的时间以及。我在这里有一个问题。如何知道哪个对象是线程安全的,哪个不是。如果我在_connection上取消锁定项目,会发生什么情况。然后我可以在同一时间添加另一个对象到同一个列表中。 – 2010-06-29 13:33:06

+0

在MSDN上,他们通常会告诉你一个对象是否是线程安全的。如果他们不说,你应该认为它不是。 您应该在添加时以及从列表中删除项目时使用锁定,否则您可能会收到意外的结果。引擎盖下的Add和Remove方法执行几行代码,当你同时调用它们时,它们可能会咬人。锁定它会使一个线程等待另一个线程释放它的锁,所以它们不会互相干扰。 – 2010-06-29 14:00:50

1

在C#中,我认为在CLR中,每个对象可能都有一个与之关联的monitor。这里_connections是一个集合,它可能与从这个非常功能启动的线程共享(它们可能在完成时从集合中删除连接)。 C#中的集合默认是不同步的,你必须明确地这样做,因此lock(_connections)声明可以防止集合上的races

+0

提供了不错的链接。 THX – 2010-06-29 13:35:03