0

Good day Everyone, I am new to multithreading coding and I have task to change the flow of currently working console application. Currently when console application start it goes through following code. "Task.Factory.Startnew" method start new thread and run "CheckDatabaseFieldStatus" which is checking status of Database table field. If this field has "cancelling" value then it will call Token.cancel() method.

Meanwhile, current thread is executing some sort of logic and keep calling "CheckCancelTokenStatus" function to throw "ThrowIfCancellationRequested" exception.

New requirement: I want to stop current thread from another thread which is created by "Task.Factory.Startnew" method. How can I achieve forceful cancellation of current thread from another thread in safe way?

Here is code:

public CancellationTokenSource TokenSource = new CancellationTokenSource();
public CancellationToken Token = TokenSource.Token;
try
{

// Spin up a task that will keep checking the request to see if it has been cancelled.
Task cancelCheck = Task.Factory.StartNew(CheckDatabaseFieldStatus, TaskCreationOptions.LongRunning);

//Some logic to finish task

CheckCancelTokenStatus(Token);

//Some logic to finish task

CheckCancelTokenStatus(Token);

//Some logic to finish task

CheckCancelTokenStatus(Token);

//Some logic to finish task

}
catch (OperationCanceledException){
    
   
   //Database call to Update status of task to canceled

}

//here is dispose method dispose token

Here is function "CheckDatabaseFieldStatus"

public void CheckDatabaseFieldStatus()
        {
            // While a Request is running, we're going to keep polling to check if we want to cancel.
            while (!Token.IsCancellationRequested)
            {
                // Using the request timer here for our wait would mean that requests could take up to 30 
               seconds to finish after they've actually finished.
                Thread.Sleep(5000);

                // Create a new context with each check to avoid conflicts with main context
                using (DbContext mydb= new DbContext())
                {
                    

                    // Get the newest version of the request and check if it's set to cancel.
                    if (mydb.Table.GetAll().Any(r => r.Status=="cancelling"))
                       {
                        TokenSource.Cancel();
                       }
                }
            }
      }

Here is function CheckCancelTokenStatus

function CheckCancelTokenStatus(CancellationToken Token)
{
     if (Token.HasValue && Token.Value.IsCancellationRequested)
         {
               Token.Value.ThrowIfCancellationRequested();
          }
}
BigB
  • 1
  • 2
  • "How can I achieve forceful cancellation of current thread from another thread in safe way?" - you cannot. There is no way to safely force the cancellation of a thread. – Enigmativity Feb 06 '21 at 00:28

1 Answers1

0

Instead of using Thread.Sleep try use Task.Delay(int milliseconds, CancellationToken token). Task.Delay creates task that will complete after given delay. If token is cancelled during wait, it will throw exception and execution will stop. Also better to check before and after waiting for cancellation, because somebody could cancel execution while you were sleeping.

public void CheckDatabaseFieldStatus()
        {
            while (!Token.IsCancellationRequested)
            {
                Task.Delay(5000, Token).GetAwaiter().GetResult();
                Token.ThrowIfCancellationRequested();

                using (DbContext mydb= new DbContext())
                {
                    if (mydb.Table.GetAll().Any(r => r.Status=="cancelling"))
                    {
                        TokenSource.Cancel();
                    }
                }
            }
      }

Also I'm using GetAwaiter().GetResult() instead of simple Wait() because second option wraps exception. See this answer for explanation https://stackoverflow.com/a/38530225/10339675

In general it's better to use async/await instead of synchronously wait

JL0PD
  • 3,698
  • 2
  • 15
  • 23
  • This is finishing thread that is created by Task.Factory.StartNew . But I also want stop to main thread immediately. Right now, main thread only throw ThrowIfCancellationRequested exception if it goes into CheckCancelTokenStatus function. But if something breaks in between of calling "CheckCancelTokenStatus" function then status in database will stay "cancelling" instead of "cancelled". – BigB Feb 05 '21 at 16:18