2011-03-28 173 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