Since you already create (and save) your tasks, the easiest fix would be to await them for each iteration of your while loop:
while (run)
{
action2();
foreach (Task t in continutask)
await t;
}
That way, when all pings completed (successful or not) you start the entire process again – without delay.
One more thing: You could add a textBox1.ScrollToEnd();
to PrintResult
Since there is a lot of room for improvement, below is a rewritten and simplified example. I’ve removed a lot of unused variables (e.g. seqnum
) and made the PingStart
method completely asynchronous. I also replaced your ListBox with a TextBox for easier testing, so you might want to revert that in your code.
This still isn’t the cleanest of all possible implementations (mainly because of the global run
) but it should show you how to do things “more async” 🙂
private async void buttonStart_Click(object sender, EventArgs e)
{
// If the ping loops are already running, don't start them again
if (run)
return;
run = true;
// Get all IPs (in my case from a TextBox instead of a ListBox
string[] ips = txtIPs.Text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
// Create an array to store all Tasks
Task[] pingTasks = new Task[ips.Length];
// Loop through all IPs
for(int i = 0; i < ips.Length; i++)
{
string ip = ips[i];
// Launch and store a task for each IP
pingTasks[i] = Task.Run(async () =>
{
// while run is true, ping over and over again
while (run)
{
// Ping IP and wait for result (instead of storing it an a global array)
var result = await PingStart(ip);
// Print the result (here I removed seqnum)
PrintResult(result.Item2);
// This line is optional.
// If you want to blast pings without delay,
// you can remove it
await Task.Delay(1000);
}
}
);
}
// Wait for all loops to end after setting run = false.
// You could add a mechanism to call isPing.SendAsyncCancel() instead of waiting after setting run = false
foreach (Task pingTask in pingTasks)
await pingTask;
}
// (very) simplified explanation of changes:
// async = this method is async (and therefore awaitable)
// Task<> = This async method returns a result of type ...
// Tuple<bool, string> = A generic combination of a bool and a string
// (-)int seqnum = wasn't used so I removed it
private async Task<Tuple<bool, string>> PingStart(string ip)
{
Ping isPing = new Ping();
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions {DontFragment = false};
// await SendPingAsync = Ping and wait without blocking
PingReply reply = await isPing.SendPingAsync(ip, timeout, buffer, options);
string rtt = reply.RoundtripTime.ToString();
bool success = reply.Status == IPStatus.Success;
string text;
if (success)
{
text = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else
{
text = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
// return if the ping was successful and the status message
return new Tuple<bool, string>(success, text);
}
This way you will have a loop for each IP that will continue independently of each other until run
is set to false
.
8
solved Why is the Windows Forms UI blocked when executing Task with ContinueWith?