在Microsoft .Net中设置线程处理器关联

时间:2012-09-08 07:01:04

标签: .net cpu affinity

(发布这个答案,因为我无法找到如何在任何地方执行此操作的完整说明,所以我认为它可能对某人有一些价值)

如何设置Microsoft .Net中特定线程的处理器关联?通过System.Diagnostics.Process.ProcessorAffinity设置进​​程的亲和性是微不足道的,但System.Threading.Thread类不提供此类功能,.Net不保证托管线程链接到任何特定的操作系统线程。

1 个答案:

答案 0 :(得分:30)

托管和操作系统线程之间的分离可以追溯到.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方法(或PInvoke GetCurrentThreadId函数,但这不适用于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,但理论上缺乏对托管线程绑定到操作系统线程的保证,将来可能会破坏此代码。但是,我认为这不太可能。

相关问题