异步代码在控制台中工作,但在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();
    }
}

异步代码在控制台中工作,但在Windows窗体中不起作用

是的,当你在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

相关文章: