我花了几天时间在 Google 中搜索并试图了解为什么在我的情况下 Windows Forms UI在Tasks中执行 ping 时被阻止。我看到很多类似的案例,但没有一个能解释我的具体案例。
问题描述:
我有一个异步发送 ping 的应用程序。每个 ping 都在任务内部发送。我.ContinueWith
用来接收 ping 的结果并将其打印到文本框而不阻塞 UI 线程。如果我启动所有 ping 一次,它工作正常。如果我添加一个while {run}
循环以使它们永远运行,我的 UI 将变得无响应并被阻止,并且没有任何结果打印到文本框。
有问题的代码:
Action action2 = () => {
for (int i = 0; i < ipquantity; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true) // Variable helps to check if ping reply was received and printed
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
Thread.Sleep(1000);
}
问题:
- 为什么 UI 会被
while
循环阻塞,为什么没有循环不会阻塞? - 如何修改我的代码以仍然能够在不阻塞 UI 的情况下使用 Tasks 进行 ping?
- 有没有更好的方法可以同时向多个 IP 地址发起无休止的 ping 操作?
完整代码:
private async void buttonStart_Click(object sender, EventArgs e)
{
run = true;
int count = listView1.Items.Count;
task = new Task<string>[count];
result1 = new string[count];
finished = new bool[count];
continutask = new Task[count];
for (int i = 0; i < count; i++)
{
finished[i] = true;
}
Action action2 = () =>
{
for (int i = 0; i < count; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true)
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
//await Task.Delay;
//Thread.Sleep(1000);
}
}
public void PrintResult(string message, int seqnum)
{
Action action = () =>
{
textBox1.AppendText(message);
textBox1.AppendText(Environment.NewLine);
textBox1.AppendText("");
textBox1.AppendText(Environment.NewLine);
};
if (InvokeRequired)
Invoke(action);
else
action();
finished[seqnum] = true;
}
public string PingStart(string ip, int seqnum)
{
finished[seqnum] = false;
Ping isPing = new Ping();
PingReply reply;
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
options.DontFragment = false;
reply = isPing.Send(ip, timeout, buffer, options);
string rtt = (reply.RoundtripTime.ToString());
string success = "N/A";
if (reply.Status == IPStatus.Success)
{
success = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else if (reply.Status != IPStatus.Success)
{
success = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
return success;
}