Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.Factory.StartNew guaranteed execution sequence

I have 2 threads calling "Task.Factory.StartNew". Let's just say that one thread (ThreadA) is slightly ahead than the other (ThreadB).

... in thread A, invoked slightly ahead

Task.Run(() => {
  SomeMethodInThreadA();
});

... in thread B, invoked slightly later

Task.Run(() => {
  SomeMethodInThreadB();
});

Does the TaskScheduler guarantee that SomeMethodInThreadA gets executed first before SomeMethodInThreadB?

If not, how do I do this? Use Task.Factory.StartNew and pass in special TaskScheduler?

Also, besides guaranteeing that SomeMethodInThreadA gets processed first, I also want to make sure that SomeMethodInThreadA finishes first before executing SomeMethodInThreadB.

I have looked into using a StaTaskScheduler, but I am not sure if this is the solution.

EDIT:

Without giving out too much details/drama about the program I inherited, I guess what I am looking for is a custom TaskScheduler which:

  1. Honors the sequence when the delegate is queued

  2. Executes them serially

  3. Do it in the same thread, similar to the StaTaskScheduler source code that I linked above

like image 734
alpinescrambler Avatar asked Apr 28 '26 09:04

alpinescrambler


1 Answers

Without giving out too much details/drama about the program I inherited, I guess what I am looking for is a custom TaskScheduler which:

  1. Honors the sequence when the delegate is queued

  2. Executes them serially

  3. Do it in the same thread, similar to the StaTaskScheduler source code that I linked above

If that is all you want all you need to do is make a BlockingCollection<Action> then loop through the list on a dedicated thread.

public class BackgroundJobSchedueller
{
    readonly BlockingCollection<Action> _queue;
    readonly Thread _thread;

    public BackgroundJobSchedueller()
    {
        _queue = new BlockingCollection<Action>()
        _thread = new Thread(WorkThread)
        {
            IsBackground = true,
            Name = "Background Queue Processor"
        };
        _thread.Start();
    }

    public void StopSchedueller()
    {
        //Tell GetConsumingEnumerable() to let the user out of the foreach loop
        // once the collection is empty.
        _queue.CompleteAdding();

        //Wait for the foreach loop to finish processing.
        _thread.Join();
    }

    public void QueueJob(Action job)
    {
        _queue.Add(job);
    }

    void WorkThread()
    {
        foreach(var action in _queue.GetConsumingEnumerable())
        {
            try
            {
                action();
            }
            catch
            {
                //Do something with the exception here
            }
        }
    }
}

When there is no work to do the thread sleeps, blocked on the foreach, once you add a item to the queue it gets processed then goes back to sleep.

like image 157
Scott Chamberlain Avatar answered May 01 '26 07:05

Scott Chamberlain



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!