首先要搞清楚的是,托管代码中的线程(Thread)并不是真的线程(OS Thread)。它只是逻辑上我们划定的线程。逻辑上的线程并不执行,实际执行的是物理线程或者叫OS线程。而通常来说,每一个逻辑线程都对应的关联于某一条物理线程,这种关系一直维系到该逻辑线程的生命周期结束。要设置线程的处理器依赖我们先要得到当前实际运行的物理OS Thread或者叫物理线程,这时候需要使用Windows API – GetCurrentThreadId `ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
class KernalHelper`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        [DllImport("kernel32")]`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
      public static extern int GetCurrentThreadId(); `ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    }
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
然后再通过当前的osThreadID找到对应的ProcessThread,并设定其ProcessorAffinity`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
以下代码演示了如何在一台双核PC的资源管理器里划出正弦曲线:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
#region private fields`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        private static int rounds = 0;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        private static int MAXROUND = 60;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        private static long[] sins = new long[MAXROUND];`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        private static PerformanceCounter pc;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        private static bool tag = false;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        #endregion`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        static void Main(string[] args)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            Thread WatchThread = new Thread(() => GenerateSin(1));`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            WatchThread.Start();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            Console.WriteLine("Press any key to break");`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            Console.ReadKey();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            WatchThread.Abort();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        public static void GenerateSin(int num)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            //对当前物理线程设置处理器依赖`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            int osThreadId = KernalHelper.GetCurrentThreadId();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            foreach (ProcessThread pt in Process.GetCurrentProcess().Threads)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                if (osThreadId == pt.Id)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                  pt.ProcessorAffinity = (IntPtr)num;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            } `ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            try`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                tag = true;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                //获得处理器的使用率`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                pc = new PerformanceCounter("Processor", "% Processor Time", "_Total");`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                for (int a = 0; a < MAXROUND; a++)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    //六十个点的,振幅为5000000周期为60的正弦序列`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    sins[a] = (long)(5000000 * Math.Sin(Math.PI * a / (double)MAXROUND * 2f)) + 5000000;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                long t1, t2;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                long TimeSlide;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                while (tag)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    t1 = pc.RawValue + sins[rounds % MAXROUND];`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    TimeSlide = Stopwatch.GetTimestamp() + Stopwatch.Frequency;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    t2 = TimeSlide - Stopwatch.Frequency + sins[rounds % MAXROUND] * Stopwatch.Frequency / 10000000;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    while (pc.RawValue < t1)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                        Thread.Sleep(10);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    while (Stopwatch.GetTimestamp() < TimeSlide) ;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                    rounds++;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            catch (Exception ex)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                Console.Write(ex.Message);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            finally`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
                pc.Close();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        }
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
效果:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
关于更多控制CPU使用率的有趣思考请看<编程之美 - 微软技术面试心得>`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
逻辑线程对CPU而言并不直接具有任务的性质,它只是一个CLR层面的数据结构,并不是OS层面实际的活动对象,逻辑线程与OS物理线程的依赖关系由CLR维护。这确实有一点点抽象,不过在托管的应用程序层面你基本上不需要关心你定义的线程和底层的线程是如何映射的。因为OS的线程调度能力比人工额外编码控制要好得多,除非你确实是有非常特殊的任务需要做,或者需要硬件层面的内存映射,否则就不要更改进程和处理器的依赖关系以及托管线程和OS线程的依赖关系。我不知道为什么.NET Framework中还提供了相应的方法和属性帮助程序员实现这样的既不“优雅”也不“安全”的功能,这显得和.NET一贯的作风有些不搭调。`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
默认情况下CLR并不保证每一个线程都始终运行在同一个处理器上,很可能在下一个时间片上线程会交由另一个处理器处理。为了避免这种情况,只能显式的指定处理器依赖情况。不过一般来说,OS都会试图保证所有UI线程都运行在发起它们的处理器上。所以还是觉得实际上除了这种趣味性的程序和某些极端测试,没有必要对此进行人工干涉。`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7