Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async Operation In Destructor

Trying to run async operation in class destructor is fail.

This is the code:

public class Executor
    {
        public static void Main()
        {
            var c1 = new Class1();

            c1.DoSomething();
        }
    }

    public class Class1 
    {
        public void DoSomething()
        {

        }

        private int _i = 100;
        private int _j = 100;

        ~Class1()
        {
            Task.Run(() => _j *= 2); //Does not progress _j
            _i *= 2; //Progress _i from 100 to 200

            Thread.Sleep(1000);
            Console.WriteLine("In destructor. _i = " + _i);
            Console.WriteLine("In destructor. _j =  " + _j);
        }
    }

And the output is:

In destructor. _i = 200
In destructor. _j =  100

Following Destructor page on MSDN does not mention threads/async aspects of instance destruction.

So any ideas?

Thank you

like image 960
Roi Shabtai Avatar asked Feb 26 '26 07:02

Roi Shabtai


1 Answers

In your particular example new thread cannot be started because runtime is terminating and app domain is unloading. When app domain unloads - it will run all finalizers and shutdown all threads. You can verify this with:

Console.WriteLine("shutdown:" + Environment.HasShutdownStarted);

Which will return true in your case. If you modify you example like this:

class Program {
    static void Main(string[] args) {
        var c1 = new Class1();
        c1.DoSomething();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.ReadKey();
    }        
}

public class Class1
{
    public void DoSomething()
    {

    }

    private volatile int _i = 100;
    private volatile int _j = 100;

    ~Class1()
    {
        Console.WriteLine("shutdown:" + Environment.HasShutdownStarted);
        Task.Run(() => _j *= 2); //Does not progress _j
        //_i *= 2; //Progress _i from 100 to 200            
        Thread.Sleep(1000);
        Console.WriteLine("In destructor. _i = " + _i);
        Console.WriteLine("In destructor. _j =  " + _j);
    }
}

And compile in Release mode with optimizations - you will see that now runtime is not terminating and your task will run fine.

Obviously you should never do such things in finalizer, but just so that you know the real reason.

like image 129
Evk Avatar answered Feb 28 '26 21:02

Evk