How to pause task execution

11,040

Solution 1

I believe it is fine to do this but preferable to use TaskCreationOptions.LongRunning.

Task.Factory.StartNew(() =>
                    {
                        ExtractStuff(fileName);
                    },TaskCreationOptions.LongRunning);

Solution 2

Thread.Sleep will block the thread running the Task (which is not ideal), but it can be an acceptable compromise (low risk and not a huge problem to performance) as long as you're not running a large number of tasks in parallel. .NET 4.5 has some improvements with 'async/await' and Task.Delay that will implicitly set up a continuation based on a timer (which doesn't require blocking a running thread), but this is not directly available in 4.0.

You can do the same thing yourself with something like this (not tested much, so use with caution):

class Program
{
    static void Main(string[] args)
    {
        var fullAction = RunActionsWithDelay(DoSomething, 2000, DoSomethingElse);
        fullAction.Wait();
        Console.WriteLine("Done");
        Console.ReadLine();
    }

    static Task RunActionsWithDelay(Action first, int delay, Action second)
    {
        var delayedCompletion = new TaskCompletionSource<object>();
        var task = Task.Factory.StartNew(DoSomething);
        task.ContinueWith(t =>
        {
            if (t.IsFaulted)
            {
                delayedCompletion.SetException(t.Exception);
            }
            else
            {
                Timer timer = null;
                timer = new Timer(s =>
                {
                    try
                    {
                        DoSomethingElse();
                        delayedCompletion.SetResult(null);
                    }
                    catch (Exception ex)
                    {
                        delayedCompletion.SetException(ex);
                    }
                    finally
                    {
                        timer.Dispose();
                    }
                }, null, delay, Timeout.Infinite);                    
            }

        });
        return delayedCompletion.Task;
    }

    static void DoSomething()
    {
        Console.WriteLine("Something");
    }

    static void DoSomethingElse()
    {
        Console.WriteLine("Something Else");
    }
}

This is fairly ugly, though you can encapsulate it a bit better than the above. It does eliminate the 'hanging' thread, but there is additional performance overhead associated with setting up the continuations. I really only recommend doing this if you have a lot of parallel tasks running and they all need to introduce delays.

Solution 3

If you need to delay the execution of ExtractStuff you can take a look at ThreadPool.RegisterWaitForSingleObject and combine with an WaitHandle that is never set.

private static WaitHandle NeverSet = new WaitHandle();
private void ExtractStuff(object state)
{
    string filename = state as string;
    ....
}

private void StartExtract(string filename);
{
    ThreadPool.RegisterWaitForSingleObject(NeverSet, ExtractStuff, fileName, seconds * 1000, true);
}

Hope that this will help you in your quest.

Share:
11,040
user1615362
Author by

user1615362

Updated on June 04, 2022

Comments

  • user1615362
    user1615362 almost 2 years

    I have this code that creates a task:

     Task.Factory.StartNew(() =>
                            {
                                ExtractStuff(fileName);
                            });
    

    Sometimes I need to pause for few seconds inside ExtractStuff

    Is it OK to use the regular Thread.Sleep(1000)? Or is there another way to pause the running task?

  • user1615362
    user1615362 over 11 years
    No, I don't need to delay the execution of ExtractStuff. I need to pause the execution of ExtractStuff in the middle based on internal logic.
  • James Manning
    James Manning over 11 years
    I don't understand how this is related to the question?
  • Dan Bryant
    Dan Bryant over 11 years
    @James, this hints to the task scheduler that your Task may take a while to execute and therefore it should avoid tying up a limited resource (like the thread pool) with your Task. This may incur some additional overhead (from allocating a new thread rather than using a thread in the pool) but it may prevent other problems (multiple tasks taking up the pool and promptly sleeping, preventing other tasks from starting.) The takeaway is that if you plan to Sleep in your Task, you probably should consider yourself long-running.
  • user1615362
    user1615362 over 11 years
    You say that Thread.Sleep will block the thread running the Task, but if I use LongRunning, wouldn't this result in only the task being paused and not the thread running the Task?
  • PMC
    PMC over 11 years
    +1, and thanks for expanding my answer, should have came back to it.
  • svick
    svick over 11 years
    @user1615362 Thread.Sleep() always blocks the current thread. If you use LongRunning, it won't be a thread from the ThreadPool, but it will still be some thread, so it's still wasteful.
  • user1615362
    user1615362 over 11 years
    @svick Your answer is complete nonsense. "but it will still be some thread" Of course it will be some thread, it will be the thread that I want to pause.
  • svick
    svick over 11 years
    @user1615362 In that case, I really don't understand the question in your first comment. You first say that you expect that a thread won't be blocked by Sleep() and then you say that of course it will be blocked?
  • Dan Bryant
    Dan Bryant over 11 years
    @user1615362, Thread.Sleep will block the thread on which the Task is executing. Using a Timer (as above or with the new Task.Delay functionality in .NET 4.5) will register a timer continuation for callback on a thread pool thread, which means that no thread will be blocked while the Task is paused (the thread that was executing the first part is released back to the pool). The latter is valuable in cases where you have multiple tasks that require pausing and you want to allow other tasks to run during the gaps while they are paused, without having to allocate a bunch of dedicated threads.
  • user1615362
    user1615362 over 11 years
    @DanBryant I understand what you are saying, but the code above is overcomplicated which makes it invalid IMO. I am looking for one line solutions. I am not planning to impress anyone with a coding extravaganza and so will use the dedicated threads instead.
  • Dan Bryant
    Dan Bryant over 11 years
    @user1615362, Agreed, this is only worthwhile if you really need it, due to having many tasks requiring long and/or frequent delays. Async/await and Task.Delay make this much simpler, as then the compiler takes care of creating all of the above ugly code for you.