异步代码在控制台中工作,但在Windows窗体中不起作用
本文关键字:但在 Windows 窗体 不起作用 工作 代码 控制台 异步 | 更新日期: 2023-09-27 18:11:11
我正在尝试编写一个应用程序,该应用程序不断在局域网上搜索主机。当我把它作为控制台运行时,count . wait()似乎工作得很好。然而,当我将代码带入窗口形式时,count . signal()似乎不会减少其计数器。我不知道是什么问题。
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();
}
}
是的,当你在Winforms项目中使用它时,你的代码会死锁。问题是Ping类尽最大努力在调用SendAsync()的同一个线程上引发PingCompleted事件。它使用AsyncOperationManager.CreateOperation()方法来执行此操作。
问题是,这实际上在Winforms应用程序中工作。它试图在主线程上引发事件。但是这不能工作,因为你用count . wait()调用阻塞了主线程。由于主线程被阻塞,ping无法完成。主线程无法完成,因为ping未完成。死锁的城市。
它在控制台模式应用程序中工作,因为它没有像Winforms那样的同步提供程序。PingComplete事件将在线程池线程上引发。
阻塞UI线程从根本上是有缺陷的。快速修复方法是在工作线程上运行代码。注意,这也会在该worker上触发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()调用
您的等待处理程序在线程池中的线程下运行。你需要回到UI线程来更新UI(由于UI运行在消息循环上)——为此你使用SynchronizationContext
这里有更多关于如何使用它的信息:http://www.codeproject.com/KB/threads/SynchronizationContext.aspx