0

The following program counts to hundret from two threads, both using the same iterator variable i.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;

namespace Threads
{
    class Program
    {
        static int i = 0;

        [DllImport("Kernel32.dll"), SuppressUnmanagedCodeSecurity]
        public static extern int GetCurrentProcessorNumber();

        static void Main(string[] args)
        {
            object lockObject = new object();
            var t1 = new Thread(CountToHundret);
            var t2 = new Thread(CountToHundret);

            t1.Start(lockObject);
            t2.Start(lockObject);

            Console.ReadKey();
        }

        private static void CountToHundret(object lockObject)
        {
            while (i < 100)
            {
                lock (lockObject)
                {
                    Console.WriteLine(
                        ++i + "/" +
                        Thread.CurrentThread.ManagedThreadId + "/" +
                        GetCurrentProcessorNumber());
                }
            }
        }
    }
}

After each count, the counting thread writes i, its own ID and the ID of the core it is running on to the console.

I got the information how to access the core ID from another question:

How to get the core/processor id of executing thread?

This is the output I receive:

1/3/7

2/4/10

[...]

44/4/10

45/3/7

[...]

60/3/6

61/4/0

[...]

100/4/9

Why are there only few thread ID changes in the second column?

Column three shows that this code is executed by multiple cores. So there should be parallelism, and I would expect the following to happen: thread 4 (running on a different core than thread 3) has to wait for the LockObject while thread 3 does its output to the console. Then thread 4 receives the LockObject. Now thread 4 writes to the console. In the meantime, thread 3 reaches the point where it must acquire the LockObject again. It waits until thread 4 has written its output, and then it is again thread 3's turn to acquire the LockObject, and so on.

In short: I'd expect to see thread ID changes in each single line. But why is this not the case here?

EmKay89
  • 53
  • 1
  • 6
  • Why do you assume the threads are running on different cores? If they are not actually running at the same time there is no reason for the kernel to schedule them on different cores. More the point: why do you care? – Charlieface Aug 13 '23 at 14:13
  • I assume that the threads run on different cores because I checked it putting GetCurrentProcessorNumber in the output Console.WriteLine and it shows different numbers each time the thread ID changes. – EmKay89 Aug 13 '23 at 14:37
  • I suspect the answer is mostly hyper-threading - which I assume you have enabled. When the scheduler for the waiting core realises it is going to wait for a (relatively) long time for memory access - for the lock - it will allow another thread on that core to execute, and now there will be a significant delay before the original thread on that core gets a slice of the time again. – sellotape Aug 13 '23 at 15:35
  • My guess is that even without hyper-threading enabled, most CPU scheduler algorithms will favour a reduction in the number of (expensive) contention-resolution actions, so might allow the core that has access to memory a longer slice of time (than the waiting core would prefer) before allowing the waiting core access. (Just a guess though; you could try disabling hyper-threading and see). – sellotape Aug 13 '23 at 15:37

0 Answers0