Program does not behave asynchronously

Viewed 62

I wrote a command line program that lets two robots (Lifeguard and Superhero) wander randomly in a 22x22 matrix until they get to a square with the # symbol.

The direction choice of the robot Superhero is in contrast to the robot Lifeguard not equally distributed. Superhero chooses the direction north 66% of the time.

I can start both robots asynchronously via the menu. While the data for Lifeguard is available relatively fast, the program freezes because of Superhero. I assumed that it does not freeze because I am programming asynchronously. Where is the error?

using System.Diagnostics;

class Program {
    public static async Task Main(string[] args) {
        Map map = new Map();
        Roboter l = new Roboter(map.defaultMap, "Lifesaver", 'L', 9);
        Roboter s = new Roboter(map.defaultMap, "Superhero", 'S', 10);

        map.spreadRoboters(l, s);
        View view = new View(map.defaultMap);
        Stopwatch watch = new Stopwatch();
        Random rand = new Random();
        string input = "start";
        while (input != "exit") {
            Console.WriteLine("choose an option:");
            Console.WriteLine("1 start asynchronously");
            Console.WriteLine("2 show Map");
            Console.WriteLine("3 exit.");
            input = Console.ReadLine();
            switch (input) {
            case "1":
                await StartTaskAsync(l, s, rand, watch);
                break;
            case "2":
                view.displayMap();
                break;
            case "exit":
                input = "exit";
                break;
            default:
                input = "exit";
                break;
            }

        }
    }

    static async Task StartTaskAsync(Roboter l, Roboter s, Random r, Stopwatch watch) {
        Task < string > lifesaverTask = StartLifesaverAsync(l, r, watch);

        Task < string > superheroTask = StartSuperheroAsync(s, r, watch);

        List < Task < string >> taskList = new List < Task < string >> {
            lifesaverTask,
            superheroTask
        };
        /* Task<string> completedTask = await Task.WhenAny(taskList);
         string result = await completedTask;
         Console.WriteLine(result);*/

        while (taskList.Count > 0) {
            Task < string > taskResult = await Task.WhenAny(taskList);
            if (taskResult == lifesaverTask) {
                Console.WriteLine(lifesaverTask.Result);
            } else if (taskResult == superheroTask) {
                Console.WriteLine(superheroTask.Result);
            }
            taskList.Remove(taskResult);
        }
    }

    static async Task < string > StartLifesaverAsync(Roboter l, Random r, Stopwatch watch) {
        return await Task.Run(() => {
            int steps = 1;
            string[] directions = new string[] {
                "NORTH",
                "SOUTH",
                "WEST",
                "EAST"
            };
            watch.Start();
            while (l.state != true) {
                int zufall = r.Next(0, 4);
                string direction = directions[zufall];
                l.move(direction, l.map);
                steps++;
            }
            watch.Stop();
            long time = watch.ElapsedMilliseconds;
            l.reset(1, 1);
            return "Lifesaver: steps: " + (steps).ToString() + ", time: " + time.ToString() + "ms";
        });
    }

    static async Task < string > StartSuperheroAsync(Roboter s, Random r, Stopwatch watch) {
        return await Task.Run(() => {
            int steps = 1;
            string[] directions = new string[] {
                "NORTH",
                "NORTH",
                "NORTH",
                "NORTH",
                "NORTH",
                "NORTH",
                "SOUTH",
                "WEST",
                "EAST"
            };
            watch.Start();
            while (s.state != true) {
                int zufall = r.Next(0, 9);
                string direction = directions[zufall];
                s.move(direction, s.map);
                steps++;
            }
            watch.Stop();
            long time = watch.ElapsedMilliseconds;
            s.reset(20, 20);
            return "Superhero: steps: " + (steps).ToString() + ", time: " + time.ToString() + "ms";
        });
    }
}
1 Answers

I think there are at least two things a play here.

A. while(...)

while(something != true){ can be dangerous because they can run forever. You don't say how long "the program freezes" for so I'm not sure, but you may have a case where s.move(direction,s.map); never sets s.State to true.

You may want to protect yourself. Here's one option:

...
steps++;
if(steps > 1_000) throw ApplicationException("Something went wrong. Too many steps taken");

B. await Task.Run

await Task.Run(() => { will wait until the work is done.

If you want to start the task but not wait until it's finished don't await immediately. Here's a little example:

using System.Diagnostics;

var sw = Stopwatch.StartNew();

var t = Task.Run(() => {  Console.WriteLine("Task 1 starting... Thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
                          Thread.Sleep(2000);// Simulate a computationally heavy work
                          Console.WriteLine("Task 1 ending... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
                       });
var t2 = Task.Run(() => {  Console.WriteLine("Task 2 starting... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
                          Thread.Sleep(2000);// Simulate a computationally heavy work
                          Console.WriteLine("Task 2 ending... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
                       });

Console.WriteLine("After starting both tasks. Task thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
await Task.WhenAll(t, t2);
Console.WriteLine("Tasks finished. Task thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(sw.Elapsed);

prints

After starting both tasks. Task thread ID: 1
Task 2 starting... thread ID: 5
Task 1 starting... Thread ID: 3
Task 1 ending... thread ID: 3
Task 2 ending... thread ID: 5
Tasks finished. Task thread ID: 5
00:00:02.0351754
Related