6

GetCurrentThreadId() has been deprecated, and MSDN states ManagedThreadId replaces it.

However, I'm getting different results, and the latter causes an exception in my code. My code is adapted from this post.

        public static void SetThreadProcessorAffinity(params byte[] cpus)
        {
            if (cpus == null)
            {
                throw new ArgumentNullException("cpus");
            }

            if (cpus.Length == 0)
            {
                throw new ArgumentException(@"You must specify at least one CPU.", "cpus");
            }

            // Supports up to 64 processors
            long cpuMask = 0;
            byte max = (byte)Math.Min(Environment.ProcessorCount, 64);

            foreach (byte cpu in cpus)
            {
                if (cpu >= max)
                {
                    throw new ArgumentException(@"Invalid CPU number.");
                }

                cpuMask |= 1L << cpu;
            }

            // Ensure managed thread is linked to OS thread; does nothing on default host in current .NET versions
            Thread.BeginThreadAffinity();

#pragma warning disable 618
            // The call to BeginThreadAffinity guarantees stable results for GetCurrentThreadId,
            // so we ignore the obsolete warning.
            int osThreadId = AppDomain.GetCurrentThreadId();
            osThreadId = Thread.CurrentThread.ManagedThreadId;// NOT THE SAME VALUE
#pragma warning restore 618

            // Find the ProcessThread for this thread
            ProcessThread thread = Process.GetCurrentProcess().Threads.Cast<ProcessThread>()
                .Where(t => t.Id == osThreadId).Single();

            // Set the thread's processor affinity
            thread.ProcessorAffinity = new IntPtr(cpuMask);
        }

I can see the issue is one gets the thread's process ID while the other gets the app's process ID.

How do I get this to work without using the deprecated method? The original Stack Overflow article states to use P/Invoke, but I don't know how, and that isn't what MSDN states.

Community
  • 1
  • 1
IamIC
  • 17,747
  • 20
  • 91
  • 154

1 Answers1

16

No, ManagedThreadId has no relationship at all with the operating system's thread ID. The CLR simply numbers threads, starting at 1. This is a fairly tragic side-effect of a project in the SQL Server group that tried to emulate .NET threads with fibers. The project was abandoned, they could not get it stable enough. Sadly the thread ID mapping was left the way it was when .NET 2.0 shipped. Technically the feature is still available for custom CLR hosts to implement threads the way they want, I'm not aware of any mainstream implementation actually doing so. The SQL Server group failure is a giant red flag.

The only way to bypass the obsoletion warning is to pinvoke GetCurrentThreadId(). The link takes you to do correct pinvoke declaration.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Out of curiosity, I assume the kernell32.dll call won't work under Mono? – IamIC Oct 28 '12 at 15:23
  • 2
    "#pragma warning disable 0618" in the source file where you use GetCurrentThreadId will suppress the warning. – Neutrino Nov 06 '13 at 19:21
  • 1
    Regarding Neutrino's comment, disabling [warning CS0618](http://msdn.microsoft.com/en-us/library/x5ye6x1e.aspx) will disable all Obsolete warnings in that file. This can be localized by wrapping the target code in `#pragma warning disable 0618` ...your code here... `#pragma warning restore 0618`. [`#pragma warning` reference here](http://msdn.microsoft.com/en-us/library/441722ys.aspx) – cod3monk3y Jul 27 '14 at 02:58