11

(これを行う方法の完全な説明がどこにも見つからなかったため、これを回答付きで投稿したので、誰かにとって何らかの価値があると思いました)

Microsoft .Net で特定のスレッドのプロセッサ アフィニティを設定するにはどうすればよいですか? プロセスのアフィニティの設定は を介し​​て簡単ですSystem.Diagnostics.Process.ProcessorAffinityが、System.Threading.Threadクラスはそのような機能を提供せず、.Net はマネージド スレッドが特定のオペレーティング システム スレッドにリンクされることを保証しません。

4

1 に答える 1

35

マネージド スレッドとオペレーティング システム スレッドの分離は .Net 2.0 にさかのぼり、SQL Server チームはファイバーを使用して .Net スレッドを実装する計画を立てています。これは実際にはどこにも行きませんでした。そのため、マネージド スレッドが常に同じオペレーティング システム スレッドで実行されるという保証はありませんが、実際には、これは現在のすべての .Net ホストに常に当てはまります。.Net 2.0 の導入以来、これが何年も変わっていないことを考えると、これが変わる可能性はほとんどありません。

この方法を使用することで、.Net の将来のバージョンに対しても自信を深めることができますSystem.Threading.Thread.BeginThreadAffinity。これにより、マネージ スレッドが同じオペレーティング システム スレッド上にとどまることが保証されます (したがって、既定で既に true になっているため、既定の CLR ホストでは何もしません)。他のマネージド スレッドが同じオペレーティング システム スレッドを共有できる可能性はまだあると思いますが、これはありそうになく、現在の .Net ホストでは絶対にありません。

.Net は、クラスを使用してネイティブ オペレーティング システム スレッドにアクセスする機能を提供します。System.Diagnostics.ProcessThreadこのクラスには、ProcessorAffinityプロパティを使用してスレッドのプロセッサ アフィニティを変更する機能があります。ただし、特定のマネージド スレッドをそのスレッドにリンクすることProcessThreadは、意図的に難しくなっています。

それを行う唯一の実際の方法は、スレッド自体の内部からです。メソッドを使用します (または非推奨のメソッドを呼び出したくない場合は関数をSystem.AppDomain.GetCurrentThreadIdPInvoke しますが、Windows 以外のオペレーティング システムの Mono では機能しません)。GetCurrentThreadIdその後、これをプロパティに一致させることができ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 スレッドにバインドされているという保証がないため、将来このコードが壊れる可能性があることに注意してください。しかし、私はこれが非常に可能性が低いと考えています。

于 2012-09-08T07:01:04.373 に答える