Asynchronous code that works in the console, but not in Windows Forms

I am trying to write an application that is constantly looking for a host on the LAN. When I run it as a console, since countdown.Wait () seems to work fine. However, when I cast the code in the form of a window, countdown.Signal () does not seem to decrease the counter. I don’t know what the problem is.

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(); } } 
+6
source share
2 answers

Yes, your code locks when you use it in a Winforms project. The problem is that the Ping class does its best to raise the PingCompleted event in the same thread called SendAsync (). To do this, use the AsyncOperationManager.CreateOperation () method.

The problem is that it actually works in a Winforms application. He is trying to raise the event to the main thread. But this will not work, since you blocked the main thread by calling the countdown .Wait (). Ping cannot complete since the main thread locks. The main thread cannot be executed because ping does not complete. Dead End City.

It runs in console mode because it does not have a synchronization provider such as Winforms. The PingComplete event will be raised in the threadpool thread.

Blocking the user interface thread is fundamentally wrong. A quick fix is ​​to run the workflow code. Beware that this ProbeCompleted event is also fired at this workstation. Use Control.BeginInvoke () to marshal it into the user interface thread. Or use 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()); } 

And don't forget to remove the extra call to Signal ().

+6
source

your wait handler starts under the thread from threadpool. you need to return to the user interface thread to update the user interface (due to the message loop that the user interface works with) - for this you use SynchronizationContext

Here is more information on how you like it: http://www.codeproject.com/KB/threads/SynchronizationContext.aspx

0
source

Source: https://habr.com/ru/post/899293/


All Articles