2011-03-28 170 views
2

我想使用Socket将实时数据从一台服务器广播到多台客户机。
但是,我遇到了当前实现中的并发问题。通过套接字流式传输数据

public class Connection { 
    private volatile bool readyToSend; 
    private Queue<byte[]> q; 
    private object bufferMonitor; 

    public Connection { 
     // initialize all things etc and connect 
    } 

    [...] // some other functions which are irrelevant for this problem 

    private void ClientConnected (SocketAsyncEventArgs args) { 
     // called by Thread A 
     [...] 
     readyToSend = true; 
     WaitingForResponse(args); 
    } 

    private void WaitingForResponse (SocketAsyncEventArgs) { 
     // called by Thread A 
     if (q.Count == 0) { 
      lock (bufferMonitor) { 
       Monitor.Wait(bufferMonitor); 
      } 
     } 
     if (q.Count != 0) { 
      byte[] data; 
      lock (q) { 
       data = q.Dequeue(); 
      } 
      args.SetBuffer(0, data.Length); 
      args.ConnectSocket.SendAsync(args); 
      // Will send all bytes and recall to WaitingForResponse afterwards 
     } else { 
      // Will recall this function if nothing happened. 
     } 
    } 

    internal void SendIfConnected (byte[] data) { 
     // called by Thread B 
     if (readyToSend) { 
      lock (q) { 
       q.Enqueue(data); 
      } 
      lock (bufferMonitor) { 
       Monitor.PulseAll(bufferMonitor); 
      } 
     } 
    }   
} 

这个实现的问题很简单,当一个客户端连接到readyToSend变化不是在第二个线程可见 - 第二个问题是,如果你把SendIfConnected功能的断点和更改值手动设置为true,即使执行Monitor.PulseAll,Monitor.Wait()也不会返回。

此外,我认为应该存在一些简单的解决方案,我的原始问题,并且使用一个字节[]队列直播的整个想法是不是最好的。我希望任何一点进入更好的方向。

回答

1

我不禁感到有一些信息在这里丢失。

  1. 在给出的代码中,bufferMonitor从不初始化。如果它没有在你没有包含的代码中完成,那么我会期待锁定调用失败。

  2. 您似乎在说readyToSend从未设置为true。从提供的代码中,这表明clientConnected方法永远不会被调用,或者在该方法执行之前抛出/返回。你确定clientConnected被调用吗?

  3. '放一个断点'是指哪里?

  4. 据我所知,Monitor.Wait(假设锁对象已被创建)仅在线程A进入等待状态后执行Monitor.PulseAll时才会返回。你确定这是发生事件的顺序吗?如果脉冲在等待被调用之前发生,线程将不会唤醒。

  5. 愚蠢的问题,但你确定你在同一个对象实例上调用它吗?所以队列填充正确?

+0

- readyToSend实际上设置为true,但是线程B没有看到这个/ Monitor.PulseAll被多次调用,在Monitor.Wait调用之前和之后。 – Etan 2011-03-28 12:29:31

+1

@Etan:愚蠢的问题,但你确定你在同一个对象实例上调用它吗?所以队列填充正确? – forsvarir 2011-03-28 12:34:35

+0

谢谢:P这是问题所在。有意思的是,有两个实例,客户端总是连接到没有填充队列的客户端。^^如果你希望你可以重新发布你的评论作为答案,所以我可以接受它。 – Etan 2011-03-28 13:12:03