2

On multiple thread programming, we know that when multiple thread access share static variable will get race condition and have thread safe problem, no matter how many CPU Cores. Like this link can single processor environment prevent race condition?.

I will want to know how much time it takes to run multi-threaded and have race condition code under different numbers of CPU Cores (this is just self-study and I want to know, although this is meaningless)

I write following a .NET Console sample code, it create two threads.

thread1 will do int.MaxValue times in loop and will increase one for share static variable.

thread2 will do int.MaxValue times in loop and will reduced one for share static variable.

When I use Process.GetCurrentProcess().ProcessorAffinity to set this process need multiple processor, because of race condition problems, the share static variable will not become 0 after the execution is completed, but an arbitrary value.

But I found when set this Process to only use one logical process by Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)0b00010001; or Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)0b00010010; or Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)0b00010100;

In such an environment, has only one logical processor to execute this multi-threaded program, although a race condition occurs, the overall execution result seems to be thread safe. Because no matter how many times I execute, the share static variable, Counter, the final result is always 0.

I don't know why such a phenomenon occurs, Could anyone help explain :

Under the .NET CLR, it is specified that only a single CPU Core can be used, and after execution ends, it will have thread safety features, which means Counter This share static variable will always be 0

I recorded the entire test process, and the recorded video is at this URL

[Update]

I have use the .net disassembler of Visual Studio 2019 to check following C# code for IL Code:

for (int i = 0; i < int.MaxValue; i++)
{
    Counter = Counter + 1;
}

The green area in the bottom of the disassembly code should generate a race condition, so that it will be executed under any number of CPU Cores, and the number of execution cycles will be enough, there will be problems.

enter image description here

    class Program
    {
        public static long Counter = 0;
        static void Main(string[] args)
        {
            Process.GetCurrentProcess().ProcessorAffinity =
                (IntPtr)0b00010001;

            Thread thread1 = new Thread(x =>
            {
                for (int i = 0; i < int.MaxValue; i++)
                {
                    Counter = Counter + 1;
                }
            });
            Thread thread2 = new Thread(x =>
            {
                for (int i = 0; i < int.MaxValue; i++)
                {
                    Counter = Counter - 1;
                }
            });
            thread1.Start(); thread2.Start();
            thread1.Join(); thread2.Join();
            Console.WriteLine($"Result={Counter}");
        }
    }
Vulcan Lee
  • 493
  • 4
  • 8

1 Answers1

0

When you execute your process on a single core, then all threads work in sequence. The scheduler assigns some execution time (called quantum) to the first thread. When the quantum expires, the scheduler stops that thread and runs the next thread that is ready to run. And so on. This type of multi-tasking is called pre-emptive.

Now, when you run your process on a single core, it is still possible to get a race condition and get a value for Counter different than 0. However, since these loops are simple and run very fast, most likely they get executed within a single quantum, a couple at most. Therefore, the chances to get a race condition are very, very low, close to zero.

Nick
  • 4,787
  • 2
  • 18
  • 24
  • Although the loop is simple, it will be executed many times. On my computer, it takes about 3 ~ 4 seconds to complete the full loop (by Single thread). But when I change to use multiple CPU Cores, the value for Courter will not be zero and only on single CPU Core.This strange phenomenon makes it hard for me to understand – Vulcan Lee Nov 27 '19 at 08:41
  • I tried to modify the number of loops to 50 times int.MaxValue, which made these two executions take about 580 seconds to finish. The result is that the shared static variable Counter value is 0 – Vulcan Lee Nov 27 '19 at 09:29
  • As I said: it is possible to get a race condition, chances are just low. – Nick Nov 27 '19 at 10:01