2012-09-08 5 views
7

(Posting diese mit Antwort, weil ich nicht eine vollständige Erklärung, wie zu tun, um diese überall finden konnte, so dass ich dachte, es könnte einen gewissen Wert für jemanden haben)Set Thread-Prozessor Affinität in Microsoft .Net

Wie kann ich Festlegen der Prozessoraffinität eines bestimmten Threads in Microsoft .Net? Die Einstellung der Affinität des Prozesses ist trivial über System.Diagnostics.Process.ProcessorAffinity, aber die Klasse System.Threading.Thread bietet keine solche Funktionalität und .Net garantiert nicht, dass ein verwalteter Thread mit einem bestimmten Betriebssystem-Thread verknüpft ist.

Antwort

25

Die Trennung zwischen verwalteten und Betriebssystem-Threads stammt aus .NET 2.0, und plant durch das SQL Server-Team .NET-Threads mit Fasern zu implementieren. Dies ging nie wirklich irgendwo hin, also gibt es zwar keine Garantie, dass ein verwalteter Thread immer auf demselben Betriebssystem-Thread läuft, in der Praxis ist dies jedoch immer der Fall für alle aktuellen .Net-Hosts. Angesichts dessen, dass sich dies seit der Einführung von .Net 2.0 in all den Jahren nicht geändert hat, ist es unwahrscheinlich, dass sich dies jemals ändern wird.

Es ist möglich, unser Vertrauen selbst für zukünftige Versionen von .Net zu stärken, indem Sie die Methode System.Threading.Thread.BeginThreadAffinity verwenden. Dadurch wird sichergestellt, dass der verwaltete Thread im selben Betriebssystemthread verbleibt (er tut also nichts auf dem Standard-CLR-Host, da dies bereits standardmäßig der Fall ist). Ich nehme an, es ist immer noch möglich, dass andere verwaltete Threads den gleichen Betriebssystem-Thread verwenden können, aber das scheint unwahrscheinlich und ist definitiv nicht der Fall in aktuellen .Net-Hosts.

.Net bietet die Möglichkeit, mit der Klasse System.Diagnostics.ProcessThread auf native Betriebssystem-Threads zuzugreifen, und diese Klasse kann die Prozessoraffinität des Threads mithilfe der ProcessorAffinity-Eigenschaft ändern. Es wurde jedoch absichtlich schwierig, einen bestimmten verwalteten Thread mit seiner ProcessThread zu verbinden.

Der einzige wirkliche Weg, um es zu tun ist von innerhalb des Threads selbst. Verwenden Sie die System.AppDomain.GetCurrentThreadId-Methode (oder PInstallieren Sie die GetCurrentThreadId-Funktion, wenn Sie keine veraltete Methode aufrufen möchten, obwohl dies bei anderen Betriebssystemen als Windows nicht mit Mono funktionieren würde). Dies kann dann der Eigenschaft ProcessThread.Id zugeordnet werden.

Dies ermöglicht es, den Faden des Prozessors Affinität mit dem folgenden Code zu setzen (um aus dem Inneren des Thread aufgerufen werden):

/// <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); 
} 

Beachten Sie, dass während dieser Arbeiten auf die aktuellen Versionen von .Net, theoretisch Das Fehlen einer Garantie, dass verwaltete Threads an OS-Threads gebunden sind, könnte diesen Code in Zukunft brechen. Dies halte ich jedoch für äußerst unwahrscheinlich.

Verwandte Themen