Alexander
Alexander

Reputation: 691

Cancel Task inside task when timed out. C#

I'm trying to run collection of tasks. I have a procesing object model, which properties I don't know. That's is why I've created a child of this class. I have a collection of ProcesingTask objects. This is my code:

 public sealed class ProcessingTask : ProcessingObject
    {
        private CancellationTokenSource cancelToken;
        private System.Timers.Timer _timer;
        public int TimeOut {private get; set; }
        public int ProcessObjectID { get; private set; }         
        public Task ProcessObjectTask { get; private set; }
        public QueueObject queueObject { private get; set; }
        public ProcessingTask(int processObjectID)
        {          
            this.ProcessObjectID = processObjectID;
            ResetTask();               
        }
    private void InitialTimeOut()
    {
        _timer = new System.Timers.Timer(TimeOut);
        _timer.Elapsed += new ElapsedEventHandler(TimedOut);
        _timer.Enabled = true;
    }
    private void TimedOut(object sender, ElapsedEventArgs e)
    {
         cancelToken.Cancel();
         Console.WriteLine("Thread {0} was timed out...", ProcessObjectID);
        _timer.Stop();            
    }
    public void ResetTask()
    {
        cancelToken = new CancellationTokenSource();
        ProcessObjectTask = new Task(() => DoTaskWork(), cancelToken.Token);            
    }
    public void DoTaskWork()
    {
        InitialTimeOut();     
        Random rand = new Random();
        int operationTime = rand.Next(2000, 20000);               
        Thread.Sleep(operationTime);
        _timer.Stop();          
         Console.WriteLine("Thread {0} was finished...", ProcessObjectID);            
    }       
}

public class CustomThreadPool
    {
        private IList<ProcessingTask> _processingTasks;      
        public CustomThreadPool(List<ProcessingTask> processingObjects)
        {           
            this._processingTasks = processingObjects;
        }
        public void RunThreadPool(Queue<QueueObject> queue, int batchSize)
        {
            for (int i = 1; i <= batchSize; i++)
            {
                QueueObject queueObject = queue.ToArray().ToList().FirstOrDefault();

                ProcessingTask task = _processingTasks.FirstOrDefault(x => x.ProcessObjectID == queueObject.QueueObjectId);                
                task.queueObject = queue.Dequeue();
                task.TimeOut = 3000;
                task.ProcessObjectTask.Start();   
            }
        }

        public void WaitAll()
        {
            var tasks = _processingTasks.Select(x => x.ProcessObjectTask).ToArray();           
            Task.WaitAll(tasks); 
        }
    }

I need to stop DoTaskWork() if running time was timed out. I'm trying to use timer and CancellationToken. But DoTaskWork() still doing his job after TimedOut(). Is any way to resolve this issue?

Upvotes: 0

Views: 81

Answers (2)

D J
D J

Reputation: 7028

You have to implement your method DoTaskWork() accordingly.

Assume this as a sample. I am assuming that your thead is doing some continuos work rather just sleep. Otherwise you can use abort method which will just abort the thread even if its in sleep mode.

public void DoTaskWork()
    {
        InitialTimeOut();
        Random rand = new Random();
        int operationTime = rand.Next(2000, 20000);
        while (true)
        {
            if (cancelToken.IsCancellationRequested)
            {
                throw new Exception("Cancellation requested.");
            }
            Thread.Sleep(operationTime);
        }
        _timer.Stop();
        Console.WriteLine("Thread {0} was finished...", ProcessObjectID);
    }

Upvotes: 1

Gy&#246;rgy Kőszeg
Gy&#246;rgy Kőszeg

Reputation: 18013

Though you send the cancel signal, you don't do anything with that in DoTaskWork

public void DoTaskWork()
{
    InitialTimeOut();     
    Random rand = new Random();
    int operationTime = rand.Next(2000, 20000);

    // Thread.Sleep(operationTime); // this imitates a non-responsive operation

    // but this imitates a responsive operation:
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    while (!cancelToken.IsCancellationRequested
      && stopwatch.ElapsedMilliseconds < operationTime)
    {
        Thread.Sleep(10);
    }

    _timer.Stop();          
     Console.WriteLine("Thread {0} was finished...", ProcessObjectID);            
}       

Upvotes: 1

Related Questions