My Technical Notes

Saturday, 19 December 2015

C#: Pauseable and Stoppable Jobs

This `Job` class is supplied with an action which takes two `WaitHandles`, one for continuing (or pausing), and one for stopping the job completely. The `Job` instance can then be used to pause and resume the job or to stop it entirely:


public delegate void JobAction(WaitHandle continueSignal, WaitHandle stopSignal);

public class Job
{
    private ManualResetEvent ContinueSignal = new ManualResetEvent(initialState: false);
    private ManualResetEvent StopSignal = new ManualResetEvent(initialState: false);

    private Thread JobThread;

    private bool IsStarted = false;

    private JobAction Action;

    public Job(JobAction action)
    {
        this.Action = action;
    }

    // pause the job
    public void PauseJob()
    {
        if (!IsStarted)
            throw new Exception("Cannot pause a non-started job");

        ContinueSignal.Reset();
    }

    // can continue a job process
    public void ContinueJob()
    {
        if (!IsStarted)
            throw new Exception("Cannot continue a non-started job");

        ContinueSignal.Set();
    }

    // stop the job completely
    public void StopJob()
    {
        if (!IsStarted)
            throw new Exception("Cannot stop a non-started job");

        if (!ContinueSignal.WaitOne(0))
        {
            ContinueSignal.Set();
        }

        StopSignal.Set();

        JobThread.Join();
    }

    // StartJob should be non-blocking
    public void StartJob()
    {
        if (IsStarted)
            throw new Exception("Cannot start a started job");

        IsStarted = true;

        ContinueSignal.Set();
        StopSignal.Reset();

        JobThread = new Thread(() =>
        {
            Action(this.ContinueSignal, this.StopSignal);
        });

        JobThread.Start();
    }
}

The following code creates a `Job` instance by passing in an action:


var job = new Job((continueSignal, stopSignal) =>
{
    while (!stopSignal.WaitOne(0))
    {
        Console.WriteLine("{0} Hello World", DateTime.Now);

        Thread.Sleep(2000);

        continueSignal.WaitOne();
    }
});

Thereafter, we can start, pause, continue and stop the job:


// start the job:
job.StartJob();
// pause the job:
job.PauseJob();
// continue the job:
job.ContinueJob();
// stop the job completely:
job.StopJob();

No comments: