2011-10-14 10 views
6

私は常にLAN上のホストを検索しているアプリケーションを作成しようとしています。 countdown.Wait()がうまく動作するように私はこれをコンソールとして実行します。しかし、コードをWindowsフォームに持っていくと、countdown.Signal()はそのカウンタを減分していないようです。問題が何であるか分かりません。コンソールでは動作しますが、Windowsフォームでは動作しない非同期コード

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Net.NetworkInformation; 
using System.Diagnostics; 
using System.Net; 
using System.Threading; 

namespace Multi_Threaded 
{ 
    public partial class Form1 : Form 
    { 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     PortScanner ps = new PortScanner(); 
     ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted); 

     ps.run_ping_probe(); 
    } 

    void ps_ProbeCompleted(object sender, PingProbeCompletedArguments e) 
    { 
     MessageBox.Show("I found " + e.ip_adresses_list_of_host.Count.ToString() + "host(s)"); 
    } 
} 

public delegate void PingProbeCompleted(object sender,PingProbeCompletedArguments e); 
public class PingProbeCompletedArguments : EventArgs 
{ 
    public List<string> ip_adresses_list_of_host; 
} 
public class PortScanner 
{ 
    public event PingProbeCompleted ProbeCompleted; 
    static List<string> ip_adresses = new List<string>(); 

    static CountdownEvent countdown; 

    public void run_ping_probe() 
    { 
     ip_adresses.Clear(); 

     countdown = new CountdownEvent(1); 

     string ipBase = "10.125."; 
     for (int sub = 0; sub < 14; sub++) 
     { 
      for (int i = 1; i < 255; i++) 
      { 
       string ip = ipBase + sub.ToString() + "." + i.ToString(); 
       Ping p = new Ping(); 
       p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted); 
       countdown.AddCount(); 
       p.SendAsync(ip, 100, ip); 
      } 
     } 
     countdown.Signal(); 
     countdown.Wait(); 
     PingProbeCompletedArguments e = new PingProbeCompletedArguments(); 
     e.ip_adresses_list_of_host = ip_adresses; 
     ProbeCompleted(this, e); 

    } 

    private void p_PingCompleted(object sender, PingCompletedEventArgs e) 
    { 
     string ip = (string)e.UserState; 
     if (e.Reply.Status == IPStatus.Success) 
     { 
      ip_adresses.Add(ip + "\t" + e.Reply.RoundtripTime + " ms"); 
     } 
     countdown.Signal(); 
    } 
} 

答えて

0

あなたの待機ハンドラは、スレッドプールからのスレッドの下で実行されます。 あなたはUIが(原因UIがで実行されていることをメッセージループに)更新されたのは、UIスレッドに戻って取得する必要があります - そのためにあなたが

ここ

詳細についてのSynchronizationContextを使用して、どのようにそれ: http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

6

はい、コードはWinformsプロジェクトで使用するとデッドロックします。問題は、PingクラスがSendAsync()を呼び出した同じスレッドでPingCompletedイベントを発生させるために最善の努力をすることです。これはAsyncOperationManager.CreateOperation()メソッドを使用して行います。

問題は、実際にはWinformsアプリケーションで動作します。メインスレッド上でイベントを発生させようとします。しかし、あなたがブロックされたのメインスレッドはcountdown.Wait()コールで動作しません。メインスレッドがブロックされているため、pingを完了できません。 pingが完了していないので、メインスレッドは完了できません。デッドロック市。

Winformsのような同期プロバイダがないため、コンソールモードのアプリケーションで動作します。 PingCompleteイベントは、スレッドプールスレッド上に発生します。

UIスレッドをブロックすることには根本的に欠陥があります。クイックフィックスはワーカースレッド上でコードを実行することです。これにより、この作業でもProbeCompletedイベントが発生することに注意してください。 Control.BeginInvoke()を使用してUIスレッドにマーシャリングします。または、BackgroundWorkerを使用します。

private void Form1_Load(object sender, EventArgs e) { 
     PortScanner ps = new PortScanner(); 
     ps.ProbeCompleted += new PingProbeCompleted(ps_ProbeCompleted); 
     ThreadPool.QueueUserWorkItem((w) => ps.run_ping_probe()); 
    } 

余分なSignal()コールを削除することを忘れないでください。

関連する問題