2012-09-08 18 views
7

(questo distacco con risposta perché non riuscivo a trovare una spiegazione completa di come fare questo ovunque, così ho pensato che potrebbe avere qualche valore per qualcuno)Set processore affinità di thread in Microsoft .Net

Come posso impostare l'affinità del processore di un determinato thread in Microsoft .Net? L'impostazione dell'affinità del processo è banale tramite System.Diagnostics.Process.ProcessorAffinity, ma la classe System.Threading.Thread non offre tale funzionalità e .Net non garantisce che un thread gestito sia collegato a un particolare thread del sistema operativo.

risposta

25

La separazione tra thread gestiti e del sistema operativo risale a .Net 2.0 e pianifica il team di SQL Server per implementare i thread .Net utilizzando le fibre. Questo non è mai andato da nessuna parte, quindi mentre non c'è alcuna garanzia che un thread gestito sia sempre eseguito sullo stesso thread del sistema operativo, in pratica è sempre il caso per tutti gli host .Net attuali. Dato che questo non è cambiato in tutti gli anni dall'introduzione di .Net 2.0, è improbabile che questo cambierà mai.

È possibile rafforzare la nostra fiducia anche per le versioni future di .Net utilizzando il metodo System.Threading.Thread.BeginThreadAffinity. Ciò garantisce che il thread gestito rimanga sullo stesso thread del sistema operativo (quindi non fa nulla sull'host CLR predefinito, poiché questo è già vero per impostazione predefinita). Suppongo che sia ancora possibile che altri thread gestiti possano condividere lo stesso thread del sistema operativo, ma ciò sembra improbabile e non è assolutamente il caso in nessun host .Net attuale.

.Net consente di accedere ai thread del sistema operativo nativo utilizzando la classe System.Diagnostics.ProcessThread e questa classe ha la possibilità di modificare l'affinità del processore del thread utilizzando la proprietà ProcessorAffinity. Tuttavia, il collegamento di un determinato thread gestito al suo ProcessThread è stato reso deliberatamente difficile.

L'unico vero modo per farlo è dall'interno del thread stesso. Utilizzare il metodo System.AppDomain.GetCurrentThreadId (o PInvoke la funzione GetCurrentThreadId se non si desidera chiamare un metodo deprecato, anche se ciò non funzionerebbe con Mono su sistemi operativi diversi da Windows). Questo può quindi essere abbinato alla proprietà ProcessThread.Id.

Ciò rende possibile impostare affinità del processore del filo con il seguente codice (che sarà chiamato dall'interno del filo):

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

tenga presente che, mentre questo funziona su versioni correnti di Net, teoricamente la mancanza di una garanzia che i thread gestiti siano legati ai thread del sistema operativo potrebbe rompere questo codice in futuro. Tuttavia, ritengo ciò estremamente improbabile.