Alex Aparin
Alex Aparin

Reputation: 4522

Starting thread with member function

I recently came across on such piece of code (here is simplified version, which I checked and it works):

using System;
using System.Threading;

namespace Rextester
{
    public class Program
    {
        public class Foo
        {
            public Foo()
            {
                thread = new Thread(new ThreadStart(Loop));
            }

            private void Loop()
            {
            }

            private Thread thread;
        }
        public static void Main(string[] args)
        {
            var foo = new Foo();
            Console.WriteLine("How does it work??");
        }
    }
}

Why does such code work without any complains from compiler? As I understand, Thread should start from function which should be static. (or reference to object and member function should be passed anyway). But here I see only passing reference to member function. It seems like I missed big thing in c#. May be there is implicit way of passing this reference?

UPD: great thanks. I just want to add minor addition of this fact. It turns out that compiler automatically handles delegates (passes correct reference object and method). here is il code:

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  nop
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  ldarg.0
  IL_000a:  ldftn      instance void Rextester.Program/Foo::Loop()
  IL_0010:  newobj     instance void 
[mscorlib]System.Threading.ThreadStart::.ctor(object,

native int)
  IL_0015:  newobj     instance void 
[mscorlib]System.Threading.Thread::.ctor(class 
[mscorlib]System.Threading.ThreadStart)
  IL_001a:  stfld      class [mscorlib]System.Threading.Thread 
Rextester.Program/Foo::thread
  IL_001f:  ret
} // end of method Foo::.ctor

Upvotes: 3

Views: 3154

Answers (1)

Mong Zhu
Mong Zhu

Reputation: 23732

But here I see only passing reference to member function.

The documentation says to the ThreadStart that it is a delegate. It

"represents the method that executes on a Thread.
When a managed thread is created, the method that executes on the thread is represented by a ThreadStart delegate"


Thread should start from function which should be static.

This is not necessarily true. The function does not have to be static.

The documentation shows both examples. Using a static method and using an instance method:

class Test
{
    static void Main() 
    {
        // To start a thread using a static thread procedure, use the
        // class name and method name when you create the ThreadStart
        // delegate. Beginning in version 2.0 of the .NET Framework,
        // it is not necessary to create a delegate explicitly. 
        // Specify the name of the method in the Thread constructor, 
        // and the compiler selects the correct delegate. For example:
        //
        // Thread newThread = new Thread(Work.DoWork);
        //
        ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
        Thread newThread = new Thread(threadDelegate);
        newThread.Start();

        // To start a thread using an instance method for the thread 
        // procedure, use the instance variable and method name when 
        // you create the ThreadStart delegate. Beginning in version
        // 2.0 of the .NET Framework, the explicit delegate is not
        // required.
        //
        Work w = new Work();
        w.Data = 42;
        threadDelegate = new ThreadStart(w.DoMoreWork);
        newThread = new Thread(threadDelegate);
        newThread.Start();
    }
}

class Work 
{
    public static void DoWork() 
    {
        Console.WriteLine("Static thread procedure."); 
    }
    public int Data;
    public void DoMoreWork() 
    {
        Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    }
}

EDIT:

In respect to the type delegate the documentation says:

A delegate is a type that represents references to methods with a particular parameter list and return type.

In this tutorial on MSDN on deleagates you can see how it can be instantiated using the new keyword:

Instantiating a delegate Once a delegate type has been declared, a delegate object must be created and associated with a particular method. Like all other objects, a new delegate object is created with a new expression.

That means that since Loop and ThreadStart have the same return type, namely void and the same parameter list, (here empty) you can instatiate the delegate using the name of the instance method Loop.

EDIT 2:

I just was confused about using member function without reference.

This works because you declare the thread in the same class as where the method is declared.

May be there is implicit way of passing this reference?

In this context, the answer is yes. If you call a method inside a class or use the name as delegate (pointer to the method) then the this is implicit.

Upvotes: 8

Related Questions