SerG
SerG

Reputation: 1340

Call Thread.Sleep from the Task

Is it correct to use Thread.Sleep() inside the task. Or is only a timer (Task.Delay() in .Net 4.5 and latter) used with task? Or maybe another approaches exist.

Upvotes: 7

Views: 11079

Answers (3)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131180

It seems the real question is how to achieve the same effect as .NET 4.5's Task.Delay in .NET 4.0.

First, if you use Visual Studio 2012+ you can add the Microsoft.Bcl.Async nuget package to your project to enable async/await and other new functionality like Task.Delay. This is the most convenient method.

If you are using Visual Studio 2010, you can achieve the same results by creating a TaskCompletionSource that completes when a timer expires. This is already provided by the ParallelExtensionsExtras library as a set of extension methods.

The basic function is StartNewDelayed and there are many convenience overloads:

    /// <summary>Creates a Task that will complete after the specified delay.</summary>
    /// <param name="factory">The TaskFactory.</param>
    /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
    /// <param name="cancellationToken">The cancellation token that can be used to cancel the timed task.</param>
    /// <returns>A Task that will be completed after the specified duration and that's cancelable with the specified token.</returns>
    public static Task StartNewDelayed(this TaskFactory factory, int millisecondsDelay, CancellationToken cancellationToken)
    {
        // Validate arguments
        if (factory == null) throw new ArgumentNullException("factory");
        if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");

        // Check for a pre-canceled token
        if (cancellationToken.IsCancellationRequested)
            return factory.FromCancellation(cancellationToken);

        // Create the timed task
        var tcs = new TaskCompletionSource<object>(factory.CreationOptions);
        var ctr = default(CancellationTokenRegistration);

        // Create the timer but don't start it yet.  If we start it now,
        // it might fire before ctr has been set to the right registration.
        var timer = new Timer(self =>
        {
            // Clean up both the cancellation token and the timer, and try to transition to completed
            try
            {
                ctr.Dispose();
            }
            catch (NullReferenceException)
            {
                // Eat this. Mono throws a NullReferenceException when constructed with
                // default(CancellationTokenRegistration);
            }

            ((Timer)self).Dispose();
            tcs.TrySetResult(null);
        });

        // Register with the cancellation token.
        if (cancellationToken.CanBeCanceled)
        {
            // When cancellation occurs, cancel the timer and try to transition to canceled.
            // There could be a race, but it's benign.
            ctr = cancellationToken.Register(() =>
            {
                timer.Dispose();
                tcs.TrySetCanceled();
            });
        }

        // Start the timer and hand back the task...
        try { timer.Change(millisecondsDelay, Timeout.Infinite); }
        catch(ObjectDisposedException) {} // in case there's a race with cancellation; this is benign

        return tcs.Task;
    }

Most of the code deals with properly disposing of the timer and handling cancellations.

Upvotes: 2

dcastro
dcastro

Reputation: 68640

You can use Thread.Sleep inside a task. But in most situations I'd prefer to use await Task.Delay which does not block the thread.

If you're using Task.Run (which uses a ThreadPool thread), then you should try not to block the thread. As it is a shared thread, there may be other code waiting to run.

I would still use Thread.Sleep(0) when I'm done using the thread, to yield the processor and give up your time slice.

Upvotes: 8

Theraot
Theraot

Reputation: 40075

In .NET 4.5 you should use Task.Delay. In .NET 4.0, since it doesn't have Task.Delay and Thread.Sleep inside a Task is a bad practice... create a custom task, and use a timer to mark ti as completed.

Upvotes: 1

Related Questions