1

How do I allow the current thread to safely exit and perform a delete action to some resources of the thread?

I used Thread.Abort() but using that it seems that it does not release the resources. I am finding a way to allow the thread to safely exit and as soon as it exits, I want to perform the delete action.

I am writing it using C#, if any one has any examples or suggestions please contribute.

var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;                   
var task = Task.Run(() => dssPut_Command("Compile " + SystemID + "abc.dss"), tokenSource2.Token);

if (!task.Wait(TimeSpan.FromSeconds(2)))
{
    ct.ThrowIfCancellationRequested();

    bool moreToDo = true;
    while (moreToDo)
    {
        // Poll on this property if you have to do
        // other cleanup before throwing.
        if (ct.IsCancellationRequested)
        {
            // Clean up here, then...
            ct.ThrowIfCancellationRequested();
        }
        tokenSource2.Cancel();
    }               
}
Martin Verjans
  • 4,675
  • 1
  • 21
  • 48
wax
  • 43
  • 5
  • C# handles cleaning up resources itself - this is known as garbage collection. It will auto initiate collection when your computer *needs* resources to be free'd. Garbage collection *can* be quite a resource intensive process and as such it is only called when the system requires it - which is why it may appear as if your thread is still running, even though it has completed its operation. If you are wanting to cleanly *cancel* a thread or task - why not check out [Cancellation Token](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=netframework-4.8) – Mark Oct 24 '19 at 16:49

1 Answers1

2

The best way to go about this depends on your scenario, but one of my preferred ways is usually to use a CancellationToken to signal that the thread should exit gracefully.

This avoids using Thread.Abort() (which is generally not a good idea), and it allows your worker to decide when it is appropriate to cancel and it can perform any necessary clean-up.

In the code you've posted, the method that calls Task.Run() should only create the CancellationTokenSource, pass the CancellationToken into the dssPut_Command method, and set cts.CancelAfter() to set the timeout. Then, only the code inside the method dssPut_Command should be checking if cancellation is requested.

static void Main()
{
    using (var cts = new CancellationTokenSource())
    {
        // Start the worker thread and pass the
        // CancellationToken to it
        Console.WriteLine("MAIN: Starting worker thread");
        var worker = Task.Run(() => dssPut_Command(cts.Token));

        // Make the token cancel automatically after 3 seconds
        cts.CancelAfter(3000);

        // Wait for worker thread to exit
        Console.WriteLine("MAIN: Waiting for the worker to exit");
        worker.Wait();
        Console.WriteLine("MAIN: Main thread exiting after worker exited");
    }
}

static void dssPut_Command(object tokenObj)
{
    Console.WriteLine("WORKER: Worker thread started");
    var cancellationToken = (CancellationToken)tokenObj;

    // You can check if cancellation has been requested
    if (cancellationToken.IsCancellationRequested)
    {
        // If there's no need to clean up, you can just return
        return;
    }

    try
    {
        // Or you can throw an OperationCanceledException automatically
        cancellationToken.ThrowIfCancellationRequested();

        // Pass the CancellationToken to any methods you call
        // so they can throw OperationCanceledException when
        // the token is canceled.
        DoWork(cancellationToken);
    }
    catch (OperationCanceledException)
    {
        // Do any clean-up work, if necessary
        Console.WriteLine("WORKER: Worker exiting gracefully");
    }
}

static void DoWork(CancellationToken cancellationToken)
{
    // Simulating a long running operation
    Task.Delay(TimeSpan.FromMinutes(1), cancellationToken).GetAwaiter().GetResult();
}
Stephen Jennings
  • 12,494
  • 5
  • 47
  • 66
  • I have edited the summary with some codes that I have tried to implement the cancellation token, I am not sure how to use that correctly in my case. – wax Oct 24 '19 at 18:55
  • So, lets say if a task takes more than 2 second , how do I cancel the task.run . You can see my codes above in the summary – wax Oct 24 '19 at 18:58
  • You'll need to pass the CancellationToken into the dssPut_Command method. That method must be written so it knows how to cancel itself by watching the CancellationToken. CancellationTokenSource has a method CancelAfter() you can use instead of task.Wait(). – Stephen Jennings Oct 24 '19 at 21:12
  • that's a really good idea, I wish I could do that but the thing is I cannot make any changes to dssPut_Command , it is coming from some library, which is the problem. – wax Oct 24 '19 at 21:41
  • If you cannot modify dssPut_Command, then to avoid Thread.Abort you can either (a) run dssPut_Command in its own _process_ and terminate the process after the timeout, or (b) if it's not important to actually halt the method but you just want to stop waiting for it to complete, you can use a Task.Wait() overload that allows you to pass a timeout. – Stephen Jennings Oct 25 '19 at 16:16