Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8928127
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 15, 20262026-06-15T08:21:55+00:00 2026-06-15T08:21:55+00:00

So, my app needs to perform an action almost continuously (with a pause of

  • 0

So, my app needs to perform an action almost continuously (with a pause of 10 seconds or so between each run) for as long as the app is running or a cancellation is requested. The work it needs to do has the possibility of taking up to 30 seconds.

Is it better to use a System.Timers.Timer and use AutoReset to make sure it doesn’t perform the action before the previous “tick” has completed.

Or should I use a general Task in LongRunning mode with a cancellation token, and have a regular infinite while loop inside it calling the action doing the work with a 10 second Thread.Sleep between calls? As for the async/await model, I’m not sure it would be appropriate here as I don’t have any return values from the work.

CancellationTokenSource wtoken;
Task task;

void StopWork()
{
    wtoken.Cancel();

    try 
    {
        task.Wait();
    } catch(AggregateException) { }
}

void StartWork()
{
    wtoken = new CancellationTokenSource();

    task = Task.Factory.StartNew(() =>
    {
        while (true)
        {
            wtoken.Token.ThrowIfCancellationRequested();
            DoWork();
            Thread.Sleep(10000);
        }
    }, wtoken, TaskCreationOptions.LongRunning);
}

void DoWork()
{
    // Some work that takes up to 30 seconds but isn't returning anything.
}

or just use a simple timer while using its AutoReset property, and call .Stop() to cancel it?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-15T08:21:57+00:00Added an answer on June 15, 2026 at 8:21 am

    I’d use TPL Dataflow for this (since you’re using .NET 4.5 and it uses Task internally). You can easily create an ActionBlock<TInput> which posts items to itself after it’s processed it’s action and waited an appropriate amount of time.

    First, create a factory that will create your never-ending task:

    ITargetBlock<DateTimeOffset> CreateNeverEndingTask(
        Action<DateTimeOffset> action, CancellationToken cancellationToken)
    {
        // Validate parameters.
        if (action == null) throw new ArgumentNullException("action");
    
        // Declare the block variable, it needs to be captured.
        ActionBlock<DateTimeOffset> block = null;
    
        // Create the block, it will call itself, so
        // you need to separate the declaration and
        // the assignment.
        // Async so you can wait easily when the
        // delay comes.
        block = new ActionBlock<DateTimeOffset>(async now => {
            // Perform the action.
            action(now);
    
            // Wait.
            await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).
                // Doing this here because synchronization context more than
                // likely *doesn't* need to be captured for the continuation
                // here.  As a matter of fact, that would be downright
                // dangerous.
                ConfigureAwait(false);
    
            // Post the action back to the block.
            block.Post(DateTimeOffset.Now);
        }, new ExecutionDataflowBlockOptions { 
            CancellationToken = cancellationToken
        });
    
        // Return the block.
        return block;
    }
    

    I’ve chosen the ActionBlock<TInput> to take a DateTimeOffset structure; you have to pass a type parameter, and it might as well pass some useful state (you can change the nature of the state, if you want).

    Also, note that the ActionBlock<TInput> by default processes only one item at a time, so you’re guaranteed that only one action will be processed (meaning, you won’t have to deal with reentrancy when it calls the Post extension method back on itself).

    I’ve also passed the CancellationToken structure to both the constructor of the ActionBlock<TInput> and to the Task.Delay method call; if the process is cancelled, the cancellation will take place at the first possible opportunity.

    From there, it’s an easy refactoring of your code to store the ITargetBlock<DateTimeoffset> interface implemented by ActionBlock<TInput> (this is the higher-level abstraction representing blocks that are consumers, and you want to be able to trigger the consumption through a call to the Post extension method):

    CancellationTokenSource wtoken;
    ActionBlock<DateTimeOffset> task;
    

    Your StartWork method:

    void StartWork()
    {
        // Create the token source.
        wtoken = new CancellationTokenSource();
    
        // Set the task.
        task = CreateNeverEndingTask(now => DoWork(), wtoken.Token);
    
        // Start the task.  Post the time.
        task.Post(DateTimeOffset.Now);
    }
    

    And then your StopWork method:

    void StopWork()
    {
        // CancellationTokenSource implements IDisposable.
        using (wtoken)
        {
            // Cancel.  This will cancel the task.
            wtoken.Cancel();
        }
    
        // Set everything to null, since the references
        // are on the class level and keeping them around
        // is holding onto invalid state.
        wtoken = null;
        task = null;
    }
    

    Why would you want to use TPL Dataflow here? A few reasons:

    Separation of concerns

    The CreateNeverEndingTask method is now a factory that creates your “service” so to speak. You control when it starts and stops, and it’s completely self-contained. You don’t have to interweave state control of the timer with other aspects of your code. You simply create the block, start it, and stop it when you’re done.

    More efficient use of threads/tasks/resources

    The default scheduler for the blocks in TPL data flow is the same for a Task, which is the thread pool. By using the ActionBlock<TInput> to process your action, as well as a call to Task.Delay, you’re yielding control of the thread that you were using when you’re not actually doing anything. Granted, this actually leads to some overhead when you spawn up the new Task that will process the continuation, but that should be small, considering you aren’t processing this in a tight loop (you’re waiting ten seconds between invocations).

    If the DoWork function actually can be made awaitable (namely, in that it returns a Task), then you can (possibly) optimize this even more by tweaking the factory method above to take a Func<DateTimeOffset, CancellationToken, Task> instead of an Action<DateTimeOffset>, like so:

    ITargetBlock<DateTimeOffset> CreateNeverEndingTask(
        Func<DateTimeOffset, CancellationToken, Task> action, 
        CancellationToken cancellationToken)
    {
        // Validate parameters.
        if (action == null) throw new ArgumentNullException("action");
    
        // Declare the block variable, it needs to be captured.
        ActionBlock<DateTimeOffset> block = null;
    
        // Create the block, it will call itself, so
        // you need to separate the declaration and
        // the assignment.
        // Async so you can wait easily when the
        // delay comes.
        block = new ActionBlock<DateTimeOffset>(async now => {
            // Perform the action.  Wait on the result.
            await action(now, cancellationToken).
                // Doing this here because synchronization context more than
                // likely *doesn't* need to be captured for the continuation
                // here.  As a matter of fact, that would be downright
                // dangerous.
                ConfigureAwait(false);
    
            // Wait.
            await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).
                // Same as above.
                ConfigureAwait(false);
    
            // Post the action back to the block.
            block.Post(DateTimeOffset.Now);
        }, new ExecutionDataflowBlockOptions { 
            CancellationToken = cancellationToken
        });
    
        // Return the block.
        return block;
    }
    

    Of course, it would be good practice to weave the CancellationToken through to your method (if it accepts one), which is done here.

    That means you would then have a DoWorkAsync method with the following signature:

    Task DoWorkAsync(CancellationToken cancellationToken);
    

    You’d have to change (only slightly, and you’re not bleeding out separation of concerns here) the StartWork method to account for the new signature passed to the CreateNeverEndingTask method, like so:

    void StartWork()
    {
        // Create the token source.
        wtoken = new CancellationTokenSource();
    
        // Set the task.
        task = CreateNeverEndingTask((now, ct) => DoWorkAsync(ct), wtoken.Token);
    
        // Start the task.  Post the time.
        task.Post(DateTimeOffset.Now, wtoken.Token);
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a WPF app that from time to time needs to perform a
I need my app to perform a certain action when DataGrid is double clicked.
So I have a simple personal finance app that needs to perform recurring expense
My app needs feature to open iPhone/iPad Mail, contacts, Calendars settings panel and automatically
My app needs to have multiple screen e.g. one login page then another page
My app needs to install some files that can be edited by the application
My app needs to know the peer device’s IP address when my device is
My app needs to be set in iOS 5 Notification Center as 'alerts' and
My app needs many NSStrings containing differente hard coded web URLs, to be accessed
My app needs to display a graphical representation of a value ranging from -1

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.