Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi Threading Shared Local Variables

I am trying to fully understand how creating separate threads that call the same method of a class instance can effect local variables in the method.

For example I have a class with a single method (Divide)

public class Maths
{
    public int Num1;
    public int Num2;

    public void Divide()
    {
        for (long i = 0; i < 100000; i++)
        {
            Num1 = 2;
            Num2 = 2;
            int result = Num1 / Num2;
            Num1 = 0;
            Num2 = 0;
        }
    }
}

Two threads are instantiated and the divide method called as follows:

    static void Main(string[] args)
    {
        Maths m = new Maths();

        Task t1 = new Task(() => m.Divide());
        Task t2 = new Task(() => m.Divide());

        List<Task> tl = new List<Task> { t1, t2 };
        Parallel.ForEach(tl, task => task.Start());

        Console.ReadLine();
    }

}

Sometimes this code runs ok. But other times it throws a dividebyzero error on the line:

int result = Num1 / Num2;

My assumption is that one of the threads is resetting the Num1 and Num2 to zero just before the other thread calls the Num1 / Num2. Therefore causing a divide by zero exception.

This would make sense and I should use a lock but I don't understand how these local variables Num1 and Num2 are shared between the threads because my understanding was that local variables are not shared between threads?

like image 295
selams Avatar asked Mar 07 '23 13:03

selams


1 Answers

You are right that local variables are not shared between threads (typically, each time method is called, new set of it's local variables is allocated on the stack of executing thread, so local variables of each method call are completely separate and modification of one of them have no effect on the others).

But unfortunatelly Num1 and Num2 are not local variables, but fields. Fields of the same instance of a class are shared between threads.

You would need to declate them like this to make them local variables:

public class Maths
{
    public void Divide()
    {
        int Num1;
        int Num2;

        for (long i = 0; i < 100000; i++)
        {
            Num1 = 2;
            Num2 = 2;
            int result = Num1 / Num2;
            Num1 = 0;
            Num2 = 0;
        }
    }
}

Alternatively, you coud create separate instance of Maths class for each thread, so each thread would use fields Num1 and Num2 of different instances of Maths class:

static void Main(string[] args)
{
    Maths m1 = new Maths();
    Maths m2 = new Maths();

    Task t1 = new Task(() => m1.Divide());
    Task t2 = new Task(() => m2.Divide());

    List<Task> tl = new List<Task> { t1, t2 };
    Parallel.ForEach(tl, task => task.Start());

    Console.ReadLine();
}
like image 57
Ňuf Avatar answered Mar 12 '23 11:03

Ňuf