2011-10-14 11 views
6

Sto provando a scrivere un'applicazione che è costantemente alla ricerca di host su una LAN. Quando eseguo questo come una console come il countdown.Wait() sembra funzionare bene. Tuttavia quando porto il codice in una finestra, countdown.Signal() sembra non decrementare il suo contatore. Non sei sicuro di quale sia il problema.Codice asincrono che funziona in Console ma non in Windows Form

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(); 
    } 
} 

risposta

0

il gestore di attesa viene eseguito sotto una discussione dal threadpool. è necessario per ottenere nuovamente dentro il thread dell'interfaccia utente di avere l'interfaccia utente aggiornata (a causa del ciclo di messaggi che l'interfaccia utente gira su) - per utilizzare SynchronizationContext

Qui maggiori informazioni su come voi: http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

6

Sì, il codice si blocca quando lo si utilizza in un progetto Winforms. Il problema è che la classe Ping fa lo sforzo migliore per generare l'evento PingCompleted sullo stesso thread che ha chiamato SendAsync(). Utilizza il metodo AsyncOperationManager.CreateOperation() per farlo.

Il problema è che in realtà funziona in un'app Winforms. Prova ad aumentare l'evento sul thread principale. Ma questo non può funzionare dal momento che tu hai bloccato il thread principale con la chiamata countdown.Wait(). Il ping non può essere completato poiché il thread principale è bloccato. Il thread principale non può essere completato poiché il ping non viene completato. Deadlock City.

Funziona in un'app in modalità console poiché non dispone di un provider di sincronizzazione come fa Winforms. L'evento PingComplete verrà generato su un thread del threadpool.

Il blocco del thread dell'interfaccia utente è fondamentalmente errato. La soluzione rapida è eseguire il codice su un thread di lavoro. Fai attenzione che questo fa scattare anche l'evento ProbeCompleted su quel lavoratore. Utilizzare Control.BeginInvoke() per eseguire il marshalling sul thread dell'interfaccia utente. O usare 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()); 
    } 

E non dimenticare di rimuovere la chiamata di segnale aggiuntivo().

Problemi correlati