Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Garbage collection of threads

Do I need to protect Thread objects from the Garbage Collector? What about the object that contains the function that the thread runs?

Consider this simple server:

class Server{
    readonly TcpClient client;

    public Server(TcpClient client){this.client = client;}

    public void Serve(){
        var stream = client.GetStream();
        var writer = new StreamWriter(stream);
        var reader = new StreamReader(stream);

        writer.AutoFlush = true;
        writer.WriteLine("Hello");

        while(true){
            var input = reader.ReadLine();
            if(input.Trim() == "Goodbye")
                break;
            writer.WriteLine(input.ToUpper());
        }

        client.Close();
    }
}
static void Main(string[] args){
    var listener = new TcpListener(IPAddress.Any, int.Parse(args[0]));
    listener.Start();

    while(true){
        var client = listener.AcceptTcpClient();
        var server = new Server(client);
        var thread = new Thread(server.Serve);
        thread.Start();
    }
}

Should I wrap my thread objects in some sort of static collection to keep them from being swept up by the garbage collector?

Presumably, if the Thread object itself stays alive, then the Server object will live, because the thread holds a reference to the delegate which holds a reference to the target object. Or maybe the thread object itself is collected, but the actual thread continues to run. Now the Server object is up for collection. And then what happens if it tries to access its field(s)?

Garbage collection makes my head spin some times. I'm glad I usually don't have to think about it.

Given the potential gotchas here, I would like to believe that the garbage collector is smart enough not to collect thread objects when the thread itself is still executing, but I can't find any documentation saying so. Reflector is of little help here, since much of the Thread class is, unsurprisingly, implemented in MethodImplOptions.InternalCall functions. And I'd rather not dig through my old outdated copy of SSCLI for answers (both because it's a pain, and because it's not a sure answer).

like image 731
P Daddy Avatar asked Jan 18 '11 06:01

P Daddy


1 Answers

It is quite simple. The real execution thread is not Thread object. The program is executing in real Windows threads which stay alive regardless of what your .NET garbage collector does with your Thread objects. So it is safe for you; you don't need to care about Thread objects if you just want the program to keep running.

Also note that your threads don't get collected when they run, because they in fact belong to the application "roots". (Roots - it's how garbage collector knows what is alive.)

More details: A managed Thread object is accessible via Thread.CurrentThread - that is something like a global static variable and those don't get collected. As I wrote earlier: Any managed thread which was started and now executing any code (even outside of .NET), doesn't lose its Thread object, because it is firmly connected to "roots".

like image 67
Al Kepp Avatar answered Sep 22 '22 14:09

Al Kepp