Search code examples
c#asynchronousexceptiontimeouttask

Handling task timeout and exception


I have a certain Func<bool> func in C# (.NET Framework 4.8) in a WPF application and want it to be executed. I'd like to have a method that takes this kind of Funcs and returns a bool.

  1. It should run in the background and not block the UI thread. Probably I need Task<bool> for that?
  2. If it takes longer than a certain timeout limit, it should be canceled and return false.
  3. The program should wait for the task to be completed but not wait for the full time limit if it is already finished earlier.
  4. If it runs into an error, error message should be printed, the task should be canceled and the program should not crash or freeze.

Is there any sophisticated method that fullfills these requirements? The solution can also use Task<bool> instead of Func<bool> if this a better solution. It should be usable in a way similar to this:

public class Program
{
    public static void Main(string[] args)
    {
        bool result = ExecuteFuncWithTimeLimit(3000, () =>
        {
            // some code here of a specific task / function
        });
    }

    public static bool ExecuteFuncWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
    {
        // run func/task in background so GUI is not freezed
        // if completed in time: return result of codeBlock
        // if calceled due to time limit: return false
        // if error occured: print error message and return false
    }
}

Solution

  • After a time of experimenting I found a solution via aborting threads. I know its not recommended, but it works fine and does its job for me.

    public class Program
    {
        public static void Main(string[] args)
        {
            Task.Run(() =>
            {
                if (!ExecuteTaskWithTimeLimit(1000, () => { return DoStuff1(); })) return;
                if (!ExecuteTaskWithTimeLimit(1000, () => { return DoStuff2(); })) return;
                // ...
            });
        }
    
        public static bool ExecuteTaskWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
        {
            Thread thread = null;
            Exception exception = null;
    
            // do work
            Task<bool> task = Task<bool>.Factory.StartNew(() =>
            {
                thread = Thread.CurrentThread;
                try
                {
                    return codeBlock();
                }
                catch (Exception e)
                {
                    exception = e;
                    return false;
                }
            });
    
            // wait for the task to complete or the maximum allowed time
            task.Wait(timeLimit_milliseconds);
    
            // if task is canceled: show message and return false
            if (!task.IsCompleted && thread != null && thread.IsAlive)
            {
                ConsoleWriteLine("Task cancled because it timed out after " + timeLimit_milliseconds + "ms.");
                thread.Abort();
                return false;
            }
    
            // if error occured: show message and return false
            if (exception != null)
            {
                MessageBox.Show(exception.Message, "Exeption", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
    
            // if task has no error and is not canceled: return its return value
            return task.Result;
        }
    }