Home > Net >  C# WhenAll(tasks) crashes the app without any exception or error
C# WhenAll(tasks) crashes the app without any exception or error

Time:12-23

Quick Summary of the issue is that I am currently trying to create an application in Xamarin that finds the IP address of the connected PC (using SMB2). Using await Dns.GetHostAddressesAsync(Dns.GetHostName()) gets me the first three segment of the correct IP address. From here I ping all the address from 0 to 255 (for example xxx.xxx.xxx.0 -> xxx.xxx.xxx.255) and see if I get a response back.

The pinging creates a new Task for every IP address it tests (so 255) while pinging those address. Finally it will do WhenAll(task) and this is where the crash seems to be happening. The weird thing is that it doesn't crash every time but every 3-5 times that this method runs.

The pinging method:

        async Task PingAsyncCustom (List<String> testIPs)
        {
                if (Battery.PowerSource == BatteryPowerSource.Usb)
                {
                    List<Task> tasks = new List<Task>();
                    
                    foreach (string ips in testIPs) 
                    {
                        using (Ping ping = new Ping())
                        {
                            var taskPing = InitiatePing(ips, ping);
                            tasks.Add(taskPing);
                        }
                    }
                    try
                    {
                        await Task.WhenAll(tasks);
                    }
                    catch (Exception e)
                    {
                        Crashes.TrackError(e);
                        Analytics.TrackEvent("WhenAll Crash"   e.ToString());
                    }
                    Report("Waiting Finished");
                    tasks.RemoveAll(x => x.IsCompleted);
                    Report("Ping Async Finished");
                }
                else
                {
                    Report("Disconected during Ping Sweep");
                    pIps.Clear();
                }
            
        }

and the initiatePing method:

        private async Task InitiatePing (String ip, Ping ping)
        {
            var tcs = new TaskCompletionSource<PingReply>();
            var options = new PingOptions(64,true); 
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            try
            {
                Report("InitiatePing: "   ip);
                var reply = await ping.SendPingAsync(ip, 2000, buffer, options);
                if (reply.Status == IPStatus.Success)
                {
                    lock (lockObj)
                    {
                        pIps.Add(reply);
                    }
                }
            }
            catch(PingException e)
            {
                Report("PingException: "   e.ToString());
            }


        }

One more thing from output is that it seems to be creating way too many threads & sometimes, not always, it will show a fatal error: (snippet of one of my runs)

Thread started: <Thread Pool> #99
Thread started: <Thread Pool> #100
Thread started: <Thread Pool> #101
Thread started: <Thread Pool> #102
Thread started: <Thread Pool> #103
Thread started: <Thread Pool> #104
Thread started: <Thread Pool> #105
Thread started: <Thread Pool> #106
Thread started: <Thread Pool> #107
[libc] Fatal signal 7 (SIGBUS), code 1 (BUS_ADRALN), fault addr

If there are better ways to implement this, I will gladly take your advice. If not, then maybe shining some light what the exact issue is and some solutions would be greatly appreciated.

"Previous Code changes:" Originally it didn't have any try & catch in the WhenAll(task) so I added it, but it still seems to crash. Also tried removing the List once they reached completion. Also when creating new Ping(), I use using to properly dispose once done.

CodePudding user response:

For a workaround, I was able to create a limit on the list<task> so it doesn't do Task.WhenAll on 254 addresses.

Code like below:

        async Task PingAsyncCustom (List<String> testIPs)
    {
            if (Battery.PowerSource == BatteryPowerSource.Usb)
            {
                var tasks = new List<Task>();
                
                foreach (string ips in testIPs) 
                {
                    if (Battery.PowerSource == BatteryPowerSource.Usb)
                    {
                        var taskPing = InitiatePing(ips);
                        tasks.Add(taskPing);
                        if (tasks.Count() == 10)
                    {
                        try
                        {
                            await Task.WhenAll(tasks);
                            tasks.Clear();
                        }
                        catch (Exception e)
                        {
                            Analytics.TrackEvent("Whenall10 Crash"   e.ToString());
                        }
                    }
                    }
                    else
                    {
                        pIps.Clear();
                        break;
                    }
                }
            try
            {
                await Task.WhenAll(tasks);
            }
            catch (Exception e)
            {
                Crashes.TrackError(e);
                Analytics.TrackEvent("WhenAll Crash"   e.ToString());
            }
                tasks.Clear();
            }
            else
            {
                pIps.Clear();
            }
        
    }

For now the I use tasks.count() == 10 but an improvement I can think of is to remove task that is completed and replace them with new task. Currently it will wait for all 10 to finish then jump onto the next batch of 10.

  • Related