Search code examples
c#asynchronousasync-awaittask-parallel-library

Task.Run( async () => ) Blocking/Not Running All Tasks C#


The problem is that I'm trying to run RunPrivateMethod() multiple times but I'm running into blocking problems or just straight up not working when I use async/await. Rather than sharing every attempt here, I'm just putting my current version.

In RunPrivateMethod(), exeProcess.WaitForExit() method is an external program that basically reads/writes/crunches/outputs data. I tried to run this as an async task and it did not work.

I don't know if it's rational concern, but I want to limit the number of Tasks that get launched at one time so I put in Task.WaitAll() at the end of each case block. Case (1) and Case (2) always will both get run.

So, here is my code. Currently, it blocks as it loads up each task. Then only the last task seems to run. It works properly if I take out all the Task statements and run everything normally.

I would really and truly appreciate any input or help on this. Most of my tests end up locking up my system and keyboard.

public void RunSomeTasks(int group)
    {

        switch (group)
        {

            case (1):
                {
                    Task.Run(async () => await RunAsyncMethod(param1, param1, group));
                    Task.Run(async () => await RunAsyncMethod(param1, param2, group));
                    Task.Run(async () => await RunAsyncMethod(param1, param3, group));
                    Task.WaitAll();
                    break;
                }
            case (2):
                {
                    Task.Run(async () => await RunAsyncMethod(param2, param1, group));
                    Task.Run(async () => await RunAsyncMethod(param2, param2, group));
                    Task.Run(async () => await RunAsyncMethod(param2, param3, group));
                    Task.WaitAll();
                    break;
                }
        }
    }

    async Task RunAsyncMethod(string var1, string var2, string varGroup)
    {           

        ////////////////////////////////////////////
        // Use ProcessStartInfo class
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.CreateNoWindow = false;
        startInfo.UseShellExecute = false;
        startInfo.FileName = "SomeOutsideEXE";
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.Arguments = var1 + " " + var2 + " " + varGroup;
        using (Process exeProcess = Process.Start(startInfo))
        {
            // did not work -> Task.Run(() => exeProcess.WaitForExit()).Wait();
            exeProcess.WaitForExit();
        }
    }
}

I have worked countless hours on this and read Cleary's book and this latest revision is a version of this post: Aync/Await action within Task.Run() The current results are that the last task in each set works although exeProcess is launched the correct amount of time. I cannot use the keyboard while it's running.

I did obviously try a straight async method for RunSomeTasks() and then just awaited RunAsyncMethod first. I seriously could use some help and, yep, I already know that I don't know what the heck I'm doing in spite of long hours of reading and trial and error.


Solution

  • I modified your example a little, this should keep the UI from locking up. Note, I added async to the button click. Also using WhenAll and passing in the started tasks, instead of using WaitAll. (Updated for full async mode)

        private async void button1_Click(object sender, EventArgs e)
        {
            try
            {
                await RunSomeTasks(1);
                await RunSomeTasks(2);
                lblStatus.Text = "done!";
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
    
        public async Task RunSomeTasks(int group)
        {
            switch (group)
            {
                case (1):
                    {
                        var t1 = RunMethodAsync(param1, param1, group);
                        var t2 = RunMethodAsync(param1, param2, group);
                        var t3 = RunMethodAsync(param1, param3, group);
                        await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
                        break;
                    }
                case (2):
                    {
                        var t1 = RunMethodAsync(param2, param1, group);
                        var t2 = RunMethodAsync(param2, param2, group);
                        var t3 = RunMethodAsync(param2, param3, group);
                        await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
                        break;
                    }
            }
        }
    
        async Task RunMethodAsync(string var1, string var2, int varGroup)
        {
            ////////////////////////////////////////////
            // Use ProcessStartInfo class
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.CreateNoWindow = false;
            startInfo.UseShellExecute = false;
            startInfo.FileName = "SomeOutsideEXE";
            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
            startInfo.Arguments = var1 + " " + var2 + " " + varGroup;
    
            using (Process exeProcess = new Process())
            {
                var cts = new TaskCompletionSource<int>();
    
                exeProcess.StartInfo = startInfo;
                exeProcess.EnableRaisingEvents = true;
    
                exeProcess.Exited += (sender, e) =>
                {
                    try
                    {
                        cts.SetResult(exeProcess.ExitCode);
                    }
                    catch (Exception ex)
                    {
                        cts.SetException(ex);
                    }
                };
    
                exeProcess.Start();
    
                await cts.Task.ConfigureAwait(false);
            }
        }