代码之家  ›  专栏  ›  技术社区  ›  Boris

为什么performanceCounter的NextValue调用会更改线程关联掩码

  •  4
  • Boris  · 技术社区  · 14 年前

    我有一个C#项目,在这个项目中,我既要访问处理器当前的工作负载,又要确保在处理器的每个内核上运行一些特定的代码。我的问题是,访问处理器的工作负载似乎会妨碍我正确分配线程关联掩码。我这里有一些代码,说明了问题:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    namespace KernelAffinitySpike
    {
        class Program
        {
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr GetCurrentThread();
    
            private static PerformanceCounter cpuUsage;
            private static UIntPtr oldMask, newMask, testMask; // thread-level processor affinity masks.
    
            static void Main(string[] args)
            {
                InitPerformanceCounter();
    
                Console.WriteLine("Pre: thread affinity: " + CurrentThreadAffinityMask());
                if (AllKernelsAccessible())
                    Console.WriteLine("Pre: all kernels accessible");
                else
                {
                    Console.Write("Pre: some kernels not accessible: ");
                    foreach (UInt32 kernel in InaccessibleKernels())
                        Console.Write(kernel + " ");
                    Console.WriteLine();
                }
    
                float load = cpuUsage.NextValue();
    
                Console.WriteLine("Post: thread affinity: " + CurrentThreadAffinityMask());
                if (AllKernelsAccessible())
                    Console.WriteLine("Post: all kernels accessible");
                else
                {
                    Console.Write("Post: some kernels not accessible: ");
                    foreach (UInt32 kernel in InaccessibleKernels())
                        Console.Write(kernel + " ");
                    Console.WriteLine();
                }
    
                Console.ReadLine();
            }
    
            static void InitPerformanceCounter()
            {
                cpuUsage = new PerformanceCounter();
                cpuUsage.CategoryName = "Processor";
                cpuUsage.CounterName = "% Processor Time"; 
                cpuUsage.InstanceName = "_Total";
            }
    
            static UInt32 CurrentThreadAffinityMask()
            {
                oldMask = SetThreadAffinityMask(GetCurrentThread(), (UIntPtr) 3); // 3 just enables all processors on a dual core. I'm only interested in the return value.
                SetThreadAffinityMask(GetCurrentThread(), oldMask);
                return (UInt32) oldMask;
            }
    
            static List<UInt32> InaccessibleKernels()
            {
                List<UInt32> inaccessible = new List<UInt32>();
                for (int i = 0; i < Environment.ProcessorCount; i++)
                {
                    newMask = (UIntPtr)(1 << i);
                    oldMask = SetThreadAffinityMask(GetCurrentThread(), newMask);
                    testMask = SetThreadAffinityMask(GetCurrentThread(), oldMask);
                    if (newMask != testMask)
                        inaccessible.Add((UInt32) newMask);
                }
                return inaccessible;
            }
    
            static bool AllKernelsAccessible()
            {
                return InaccessibleKernels().Count == 0;
            }
        }
    }
    

    Pre: thread affinity: 3
    Pre: all kernels accessible
    Post: thread affinity: 2
    Post: some kernels not accessible: 1 
    

    所以,看起来cpuUsage.next值调用以某种方式更改了线程关联掩码,也使得无法将掩码更改为1。如果Nextvalue调用正在聚合每个内核的性能计数,那么它必须以某种方式与线程关联掩码进行交互,这是有意义的,但是我不明白为什么它会影响线程关联掩码的未来更改。有人对此问题有解释或解决方法吗?

    1 回复  |  直到 14 年前
        1
  •  1
  •   DiVan    13 年前

    这里是 some other guy with same problem

    似乎是微软的未解之谜。

    Microsoft support .