2014-09-26 35 views
2

我有一個應用程序使用.net 4.0中的任務處理FIFO隊列中的項目。在任務中使用異步套接字

我是新來的TPL和.NET任務,想知道是否有一個簡單的解決我的問題:

在任務的操作委託指派給上發送和接收數據的方法異步套接字。我遇到的問題是任務「過早地」結束。在處理隊列中的下一個項目之前,我如何讓Task等待所有通信完成?

一個解決方案是切換到使用同步套接字,但我希望有一種方法來使用異步套接字來做到這一點。

編輯 添加一些代碼:

class Program 
{ 
    private BlockingCollection<string> myQueue; 
    private CancellationTokenSource cancellationSignalForConsumeTask; 
    private CancellationTokenSource cancellationSignalForProcessCommandTask; 
    private AsyncSocket mySocket; 

    public void Main(string[] args) 
    { 
     mySocket = new mySocket(); 
     myscoket.ReceiveData += mySocket_ReceiveData; 

     cancellationSignalForConsumeTask = new CancellationTokenSource(); 
     Task listenerTask = Task.Factory.StartNew((obj) => Consume(), 
                  cancellationSignalForConsumeTask.Token, 
                  TaskCreationOptions.LongRunning); 

     while (true) 
     {} 
    } 

    private void Consume() 
    { 
     while (!myQueue.IsCompleted) 
      { 
       string _item = myQueue.Take(); 

       cancellationSignalForProcessCommandTask = new CancellationTokenSource(); 
       Task t = new Task(() => 
        { 
         cancellationSignalForProcessCommandTask.Token.ThrowIfCancellationRequested(); 
         DoSomeWork(_item); 
        }, cancellationSignalForProcessCommandTask.Token, TaskCreationOptions.LongRunning); 

       t.Start(); 
       t.Wait(); 
      } 
    } 

    private void DoSomeWork(string _item) 
    { 
     mySocket.SendData("Data to server that could take a long time to process") 
    } 

    private void mySocket_ReceiveData(string dataFromServer) 
    { 
     string returnMessage = dataFromServer; 

     //I want the Task to end here... 

    } 
} 

的問題是,在任務結束時DoSomeWork()方法完成(我明白爲什麼),是有辦法,我可以手動告訴工作結束通過CancellationTokenSource對象也許?

+0

可能是根線程/任務的Wait()。你可以展示你到目前爲止的代碼嗎? – MatthewMartin 2014-09-26 17:30:05

+0

發佈你到目前爲止。 – 2014-09-26 17:31:29

+0

什麼是'AsyncSocket'?如果'SendData()'是異步的,那麼你可能需要「等待」它。 – svick 2014-09-26 18:28:36

回答

2

如果我理解正確的話,你要伺候接收數據的任務,但你現在的任務正在等待的發送數據。這樣做的一個方法是使用一個結構類似AutoResetEvent

private AutoResetEvent autoResetEvent = new AutoResetEvent(false); 

private void Consume() 
{ 
    while (!myQueue.IsCompleted) 
     { 
      string _item = myQueue.Take(); 

      cancellationSignalForProcessCommandTask = new CancellationTokenSource(); 
      Task t = new Task(() => 
       { 
        cancellationSignalForProcessCommandTask.Token.ThrowIfCancellationRequested(); 
        DoSomeWork(_item); 
       }, cancellationSignalForProcessCommandTask.Token, TaskCreationOptions.LongRunning); 

      t.Start(); 

      // Wait for data to be received. 
      // This line will block until autoResetEvent.Set() is called. 
      autoResetEvent.WaitOne(); 
     } 
} 

private void mySocket_ReceiveData(string dataFromServer) 
{ 
    string returnMessage = dataFromServer; 

    // Notify other threads that data was received and that processing can continue. 
    autoResetEvent.Set(); 
} 

這僅僅是使用AutoResetEvent的一個例子 - 你可能會希望完善它,以滿足您的需求。

+0

嘿..你不知道它:它的工作!太棒了,謝謝你! – oGJo 2014-09-26 18:56:56

+0

請注意,在同步線程時應該小心。例如,如果'DoSomeWork'發送兩個單獨的數據字符串,則只有在收到所有數據後纔想調用Set,否則第二個任務將在第一個任務完成之前開始。 – 2014-09-26 19:02:09