2016-04-22 18 views
0

おはよう。ここでSendPingAsyncメソッドを停止する方法を教えてください。SendAsyncCancelを試しましたが、スレッドが1つだけ停止するため、すべてのpongスレッドをキャンセルする必要があります。ボタンでPing.SendAsyncを停止WPFをクリック

private void refreshbtn_Click(object sender, EventArgs e) 
    { 
     if (tokenSource != null) //check if its even initialized or not 
      tokenSource.Cancel(); 

     lstNetworks.Items.Clear(); 
     string gate_ip = NetworkGateway(); 
     //Extracting and pinging all other ip's. 
     string[] array = gate_ip.Split('.'); 
     for (int i = 1; i <= 255; i++) 
     { 
      string ping_var = array[0] + "." + array[1] + "." + array[2] + "." + i; 

      //time in milliseconds   
      Ping(ping_var, 1, 4000); 
     } 
    } 

    public void Ping(string host, int attempts, int timeout) 
    { 
     tokenSource = new CancellationTokenSource(); 
     Task.Factory.StartNew(() => 
     { 
      try 
       { 
        System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping(); 
        ping.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback); 
        ping.SendAsync(host, timeout, host); 
       } 
       catch 
       { 
        // Do nothing and let it try again until the attempts are exausted. 
        // Exceptions are thrown for normal ping failurs like address lookup 
        // failed. For this reason we are supressing errors. 
       } 
     }, tokenSource.Token); 
    } 

    private void PingCompletedCallback(object sender, PingCompletedEventArgs e) 
    { 
     // If an error occurred, display the exception to the user. 
     if (e.Reply.Status == IPStatus.Success) 
     { 

      string hostName = GetHostName(e.Reply.Address.ToString()); 
      string macAdress = GetMacAddress(e.Reply.Address.ToString()); 
      if (!Dispatcher.CheckAccess()) 
      { 

       Dispatcher.Invoke(new Action(() => 
       { 
         lstNetworks.Items.Add(new InfoItem() { IP = e.Reply.Address.ToString(), MAC = macAdress, HOST = hostName }); 
        lstNetworks.Items.SortDescriptions.Add(new SortDescription("IP", ListSortDirection.Ascending)); 
       })); 
      } 
     } 
     else { 
      //Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString())) 
     } 
    } 

私がリフレッシュボタンをクリックするたびに、新しいping操作を開始する必要があります。私の場合は、1つのpingスレッドしか停止しませんが、残りは動作し続けます。

UPDATE

あなたが書いたように私は私が再びリフレッシュボタンを押すと、すべてのスレッドが(30秒)を停止するまでの私のアプリがフリーズ、試してみました。しかし、アプリが解凍したときの結果は同じです。前回のSendAsyncのすべてのPingパケットに、2回目の送信した新しいSensAsyncパケットが追加されました。私はスレッドだけでなく、SendAsyncスレッドも停止する必要があります。メソッドSendAsyncCancelがありますが、取り消しトークンが発生したときにどのように呼び出すことができますか?

答えて

1

毎回TokenSourceの別のインスタンスを作成しています。代わりに、1つしか作成せず、同じインスタンスをすべてTasksに渡します。各Taskは、Tokenにキャンセル要求があるかどうかを確認し、すべての要求に対してWaitAllを実行して、Tokenを渡します。

private async void refreshbtn_Click(object sender, EventArgs e) 
{ 
    if (tokenSource != null) //check if its even initialized or not 
     tokenSource.Cancel(); 

    lstNetworks.Items.Clear(); 
    string gate_ip = NetworkGateway(); 
    //Extracting and pinging all other ip's. 

    tokenSource = new CancellationTokenSource(); 

    string[] array = gate_ip.Split('.'); 

    List<Task> tasks = new List<Task>(); 
    for (int i = 1; i <= 255; i++) 
    { 
     string ping_var = array[0] + "." + array[1] + "." + array[2] + "." + i; 

     var task = Task.Factory.StartNew(() => 
     { 
      if (tokenSource.Token.IsCancellationRequested) return; 

      //time in milliseconds   
      Ping(ping_var, 1, 4000, tokenSource.Token); 
     }, tokenSource.Token); 
     tasks.Add(task); 
    } 
    await Task.WhenAll(tasks.ToArray()); 
} 

public void Ping(string host, int attempts, int timeout, CancellationToken cancellationToken) 
{ 
    try 
    { 
     System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping(); 

     cancellationToken.Register(() => ping.SendAsyncCancel()); 

     ping.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback); 
     ping.SendAsync(host, timeout, host); 
    } 
    catch 
    { 
     // Do nothing and let it try again until the attempts are exausted. 
     // Exceptions are thrown for normal ping failurs like address lookup 
     // failed. For this reason we are supressing errors. 
    } 
} 

更新:

追加非同期/ので、それがUIをブロックしません待っています。各Pingのキャンセルトークンを登録して、キャンセルすることができます。

+0

あなたが書きましたように、私はすべてのスレッドが(30秒)停止するまで、私は再びリフレッシュボタンを押します。しかし、アプリが解凍したときの結果は同じです。前回のSendAsyncのすべてのPingパケットに、2回目の送信した新しいSensAsyncパケットが追加されました。私はスレッドだけでなく、SendAsyncスレッドも停止する必要があります。メソッドSendAsyncCancelがありますが、取り消しトークンが発生したときにどのように呼び出すことができますか? –

+0

更新を参照してください。 UIスレッドをブロックしないようにコードを追加し、SendAsyncCancelの使用方法を追加しました。 –

+0

問題があります。あなたのコードを追加しましたが、コンパイルエラーが発生しました。Task.WaitAll(tasks.ToArray()、tokenSource.Token); - 無効にすることはできません –

関連する問題