Dot-Net

在 Microsoft .Net 中設置執行緒處理器關聯

  • September 8, 2012

(發布這個答案是因為我在任何地方都找不到關於如何做到這一點的完整解釋,所以我認為它可能對某人有一些價值)

如何在 Microsoft .Net 中設置特定執行緒的處理器親和性?通過 設置程序的親和性是微不足道的System.Diagnostics.Process.ProcessorAffinity,但是System.Threading.Thread該類不提供此類功能,並且.Net 不保證託管執行緒連結到任何特定的作業系統執行緒。

託管執行緒和作業系統執行緒之間的分離可以追溯到 .Net 2.0,並且 SQL Server 團隊計劃使用纖程實現 .Net 執行緒。這從來沒有真正發生過,因此雖然不能保證託管執行緒將始終在同一個作業系統執行緒上執行,但實際上對於所有目前的 .Net 主機都是如此。鑑於自 .Net 2.0 推出以來的這些年裡,這種情況一直沒有改變,這種情況不太可能永遠改變。

System.Threading.Thread.BeginThreadAffinity通過使用該方法,即使對於 .Net 的未來版本,也可以增強我們的信心。這保證了託管執行緒將保持在同一個作業系統執行緒上(因此它在預設 CLR 主機上什麼也不做,因為預設情況下已經如此)。我想其他託管執行緒仍然有可能共享相同的作業系統執行緒,但這似乎不太可能,並且在任何目前的 .Net 主機中絕對不是這種情況。

.Net 提供了使用該類訪問本機作業系統執行緒System.Diagnostics.ProcessThread的能力,並且該類具有使用該ProcessorAffinity屬性更改執行緒的處理器親和性的能力。然而,將一個特定的託管執行緒連結到它ProcessThread是故意困難的。

唯一真正的方法是從執行緒本身內部。使用該System.AppDomain.GetCurrentThreadId方法(GetCurrentThreadId如果您不想呼叫已棄用的方法,則使用 PInvoke 函式,儘管這不適用於 Windows 以外的作業系統上的 Mono)。然後可以將其與ProcessThread.Id屬性相匹配。

這使得可以使用以下程式碼設置執行緒的處理器親和性(從執行緒內部呼叫):

/// <summary>
/// Sets the processor affinity of the current thread.
/// </summary>
/// <param name="cpus">A list of CPU numbers. The values should be
/// between 0 and <see cref="Environment.ProcessorCount"/>.</param>
public static void SetThreadProcessorAffinity(params int[] 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;
   foreach( int cpu in cpus )
   {
       if( cpu < 0 || cpu >= Environment.ProcessorCount )
           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();
#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);
}

請記住,雖然這適用於目前版本的 .Net,但理論上缺乏託管執行緒綁定到 OS 執行緒的保證可能會在將來破壞此程式碼。但是,我認為這極不可能。

引用自:https://stackoverflow.com/questions/12328751