Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreading and closures in .NET

If I have this:

public string DoSomething(string arg)
{
    string someVar = arg;
    DoStuffThatMightTakeAWhile();
    return SomeControl.Invoke(new Func<string>(() => someVar));
}

And this method can be called concurrently from multiple threads, and one thread is stuck at DoStuffThatMightTakeAWhile, and then a second thread calls DoSomething with a different arg, will this change the value of someVar for all threads and consequently, DoSomething return the second version of someArg on both calls, or will one someVar exist for each thread?

Edit I think my Action should have been a Func so edited it.

like image 220
Juan Avatar asked Dec 20 '11 02:12

Juan


People also ask

What is multithreading in dotnet?

Multithreading in C# is a process in which multiple threads work simultaneously. It is a process to achieve multitasking. It saves time because multiple tasks are being executed at a time. To create multithreaded application in C#, we need to use System.

What is multithreading in MVC?

The first is that every ASP.NET application (MVC or otherwise) is inherently multi-threaded: Each request will be processed on a separate thread, so you are automatically in a multi-threading situation and must consider this with any shared access to data (e.g. statics, etc.).

How does multithreading work in C#?

A thread is defined as the execution path of a program. Each thread defines a unique flow of control. If your application involves complicated and time consuming operations, then it is often helpful to set different execution paths or threads, with each thread performing a particular job.

How does .NET threading work?

A thread has a priority and every thread has its own stack, but the memory for the program code and heap are shared among all threads of a single process. A process consists of one or more threads of execution. A process always consists of at least one thread called the primary thread (Main() method in C# programs).


3 Answers

There are a number of confusions in the answers here, mostly based upon the untruth that local variables are allocated "on the stack of the thread". This is both false and irrelevant.

It's false because the local variable may be allocated on some temporary pool or the long-term storage pool; even if it is allocated on a temporary pool, that need not be stack memory; it could be a register. It's irrelevant because who cares what pool the storage is allocated on?

The relevant fact is that a top-level local variable is allocated per method activation. More generally, a local variable in a block is allocated once per the block being entered; a local variable declared in the body of a loop, for example, is allocated every time the loop goes around.

So, let's consider your question:

This method can be called concurrently from multiple threads. If one thread is stuck at DoStuffThatMightTakeAWhile, and then a second thread calls DoSomething with a different arg, will this change the value of someVar for all threads?

No. There is a new "someVar" for each activation of DoSomething.

will one someVar exist for each thread?

One "someVar" will exist for each activation. If a thread does exactly one activation then there will be exactly one someVar per thread; if a thread does a million activations then there will be a million of them.

That said, Jon Hanna's answer is also correct: if you make a delegate which both reads and writes a local variable, and you hand that delegate out to multiple threads, then all the activations of the delegate share the same local variable. There is no magical thread safety created for you; if you want to do that then you are responsible for ensuring thread safety.

like image 130
Eric Lippert Avatar answered Oct 17 '22 10:10

Eric Lippert


Local variables stored in the current thread's stack, so each thread will have its own stack and each own someVar variable in it.

Since it would be different values in each thread

new Action(() => someVar)); 

will capture it's own value of someVar.

Edit

I was simply wrong saying that, as Eric pointed. See his answer for correct explanation.

like image 31
Restuta Avatar answered Oct 17 '22 10:10

Restuta


As said, each thread hitting DoSomething is creating a separate someVar on its stack, and therefore no thread has any effect on another's someVar.

It is worth noting though, that if a local is captured in a closure and there is multi-threading initiated in that scope, that this can indeed cause different threads to affect the values each other sees, even in the case of value types (which we would normally think of as not something that another method can affect - in this way closures are not like class methods:

public static void Main(string[] args)
{
    int x = 0;
    new Thread(() => {while(x != 100){Console.WriteLine(x);}}).Start();
    for(int i = 0; i != 100; ++i)
    {
        x = i;
        Thread.Sleep(10);
    }
    x = 100;
    Console.ReadLine();
}

Demonstrates this.

like image 34
Jon Hanna Avatar answered Oct 17 '22 11:10

Jon Hanna