我正在尝试编写一个不断在局域网上搜索主机的应用程序。当我作为控制台运行它作为倒计时.Wait()似乎工作正常。但是,当我将代码带入windows窗体时,countdown.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();
}
}
答案 0 :(得分:6)
是的,当您在Winforms项目中使用它时,代码会死锁。问题是Ping类尽力在调用SendAsync()的同一线程上引发PingCompleted事件。它使用AsyncOperationManager.CreateOperation()方法来执行此操作。
问题是,这实际上适用于Winforms应用程序。它试图在主线程上引发事件。但是,由于您使用countdown.Wait()调用阻止主线程,因此无效。由于主线程被阻止,ping无法完成。由于ping未完成,主线程无法完成。死锁城市。
它在控制台模式应用程序中工作,因为它没有像Winforms那样的同步提供程序。 PingComplete事件将在线程池线程上引发。
阻止UI线程存在根本缺陷。快速解决方法是在工作线程上运行代码。请注意,这也会导致ProbeCompleted事件在该worker上触发。使用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()调用。
答案 1 :(得分:0)
你的等待处理程序在线程池的一个线程下运行。 你需要回到UI线程来更新UI(由于运行UI的消息循环) - 为此你使用SynchronizationContext
以下有关如何使用它的更多信息: http://www.codeproject.com/KB/threads/SynchronizationContext.aspx