Friday, February 27, 2015

Task Cancellation


namespace TaskCancellation
{

    public class PrimeTool
    {
        public static bool IsPrime(int candidate)
        {
            // Test whether the parameter is a prime number.
            if ((candidate & 1) == 0)
            {
                if (candidate == 2)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            for (int i = 3; (i * i) <= candidate; i += 2)
            {
                if ((candidate % i) == 0)
                {
                    return false;
                }
            }
            return candidate != 1;
        }
    }
}
//==============================================================
using System.Windows.Forms;
using System.Threading; //Added to use Cancellation

namespace TaskCancellation
{
    public partial class Form1 : Form
    {
        Random rand = new Random();

        //Declare a CancellationTokenSource giving it a class scope
        //to be able to access it from 2 buttons
        CancellationTokenSource cts = null;
        //The CancellationTokenSource provides;
        //a property Token to pass the Task constructor as well as to 
        //the method running in a task

        //It also provides a method: Cancel() to allow you to request
        //cancellation from another button.

        //Cancellation is a cooperative process.
        //Calling the Cancel method does not force cancellation, but
        //just makes a request for cancellation.
        //It is up to the method running in a task to add some code that 
        //acknowledges the cancellation request, then cancels itself


        public Form1()
        {
            InitializeComponent();
        }

        //1. define a delegate with same signature as the crosss-threading handling
        // method (the SetText method)
        private delegate void RichTextBoxHandler(string s, RichTextBox rtb);
        private void SetText(string s, RichTextBox rtb)
        {
            if (rtb.InvokeRequired)
            {
                //create a delegate object
                RichTextBoxHandler handler = SetText;
                Invoke(handler, s, rtb);
            }
            else
            {
                rtb.AppendText(s + "\n");
                //scroll down
                rtb.ScrollToCaret();
            }
        }


        //This method must have the same signature as the Action<Object> delegate
        //You are going to pass to it a CancellationToken object
        //So your method has a way to cancel the task running it.
        private void DisplayEvenRandomNumbers(Object obj)
        {
            //This method is passed a cancellation token, so you need 
            //to cast the obj
            CancellationToken token = (CancellationToken)obj;

            //Display 1,000 odd random
            int counter = 0;
            do
            {
                //check if cancellation has been requested
                if (token.IsCancellationRequested)
                {
                    //clean up resources
                    token.ThrowIfCancellationRequested();
                    //causes this method to exit, which ends or cancels the task.

                }
                int num = rand.Next();
                if (num % 2 == 0)
                {
                    // richTextBox2.AppendText(counter + "    " + num + "\n");
                    SetText(counter + "  " + num, richTextBox1);
                    //scroll down automaically
                    //rtb.ScrollToCaret();
                    counter++;
                }
            } while (counter < 1000);
        }

        private void btnStartTask_Click(object sender, EventArgs e)
        {
            //Use the constructor:
            //Task(Action<Object>, Object, CancellationToken)
            //your method must have the same signature as the 
            //Action<Object>delegate
            Action<Object> action = DisplayEvenRandomNumbers;
            //create a cancellation token to pass it to the method
            //as well as to the Task constructor

            //1. Create a CancellationTokenSource
            cts = new CancellationTokenSource();
            //Secondly, get the Token property
            CancellationToken token = cts.Token;

            //Create Task
            Task task = new Task(action, token, token);
            //one token is pass to the method, and another one is pass to the system constructor

            task.Start();
        }

        private void btnCancelTask_Click(object sender, EventArgs e)
        {
            if (cts != null) //this if statement avoid no pointer exception
            {
                cts.Cancel(); //will request cancellation
            }
        }

        private void startTaskOption2_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            //use task Constructor
            //public Task(Action action,CancellationToken cancellationToken)
            Task task = new Task(() => DisplayEvenRandomNumbers2(cts.Token), cts.Token);
                task.Start();
        }

        //method for option 2
        //Ref: https://msdn.microsoft.com/en-us/library/dd783029(v=vs.110).aspx
        private void DisplayEvenRandomNumbers2(CancellationToken tk)
        {
            //This method is passed a cancellation token, so you need 
            //to cast the obj
            
            //Display 1,000 odd random
            int counter = 0;
            do
            {
                //check if cancellation has been requested
                if (tk.IsCancellationRequested)
                {
                    //clean up resources
                    tk.ThrowIfCancellationRequested();
                    //causes this method to exit, which ends or cancels the task.

                }
                int num = rand.Next();
                if (num % 2 == 0)
                {
                    // richTextBox2.AppendText(counter + "    " + num + "\n");
                    SetText(counter + "  " + num, richTextBox1);
                    //scroll down automaically
                    //rtb.ScrollToCaret();
                    counter++;
                }
            } while (counter < 1000);
        }

        //===================================================================
        private void btnDisplayPrimeNumbers_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            //use task Constructor
            //public Task(Action action,CancellationToken cancellationToken)
            Task task = new Task(() => DisplayPrimeNumbers(cts.Token), cts.Token);
            task.Start();
        }

        //static void IsPrime()
        private void DisplayPrimeNumbers(CancellationToken tk)
        {
                for (int i = 0; i <= 3000; i++)
                {
                    if(tk.IsCancellationRequested)
                    {
                        //clean up resources
                        tk.ThrowIfCancellationRequested();
                        //causes this method to exit, which ends or cancels the task.
                    }
                    // PrimeTool created to run check from msdn
                    if (PrimeTool.IsPrime(i))
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        SetText("Prime Numbers: " + i, richTextBox1);
                    }
                }
        }

        private void btnCancelPrimeNumberTask_Click(object sender, EventArgs e)
        {
            if (cts != null) //this if statement avoid no pointer exception
            {
                cts.Cancel(); //will request cancellation
            }
        }
    }
}
//Lab
//Add new button to start a task that displays prime numbers
//provide a button to cancel it.
//=================================================================

No comments:

Post a Comment