Monday, September 11, 2017

Closures and Race Conditions

Closure = code + supporting data environment

int x = 123;

Task. Factory.StartNew( () =>
{
    x = x + 1;
}
);
...
Console.WriteLine(x);

In the example above x is called a closure variable. The compiler has to figure out how to pass the value x to the lambda expression. The compiler does this By Reference, not by value. Think of By Reference as pointers to the same memory space for the shared variable x.

So, everywhere you see x in the above example it all references the same x. This means if x is changed anywhere by any of the code including the one if the separate thread we have a race condition (since the variables are read and written).

The program could either print out 123 or 124 depending on which thread finishes first. The result is not consistent.

This means we need to take steps to make sure only one thread is read or writing the variable at a time.

Behind the scenes

The compiler will generate the following code for the code above


private sealed class c__DisplayClass2
{
public int x;
public void b__0()
{
this.x = this.x + 1;
}
}

cgobj = new c__DisplayClass2();
cgobj.x = 123;
delegate = new Action(cgobj.b__0);
Task.Factory.StartNew(delegate);
...

Console.WriteLine(cgobj.x);

Reference

Content is based on Pluralsight video called Introduction to Async and Parallel Programming in .NET 4 by Dr. Joe Hummel. 

No comments: