Windows下綁定線程到指定的CPU核心

在某些情況下,為了提升程序的執(zhí)行效率,需要將程序綁定到指定的cpu核心上。根據(jù)微軟官方文檔,windows提供了兩個win32函數(shù):setthreadaffinitymask和setprocessaffinitymask,用于設(shè)置指定線程或進(jìn)程的處理器關(guān)聯(lián)掩碼,從而實現(xiàn)線程或進(jìn)程對處理器的綁定。

SetThreadAffinityMask函數(shù)用于設(shè)置指定線程的處理器關(guān)聯(lián)掩碼,使線程在指定的CPU核心上運行。其函數(shù)定義如下:

DWORD_PTR SetThreadAffinityMask(  [in] HANDLE    hThread,  [in] DWORD_PTR dwThreadAffinityMask);

該函數(shù)需要傳遞兩個參數(shù):

  • hThread:指向要設(shè)置處理器關(guān)聯(lián)的線程句柄。如果要設(shè)置當(dāng)前線程的關(guān)聯(lián)掩碼,可以使用GetCurrentThread()函數(shù)獲取句柄。
  • dwThreadAffinityMask:處理器的關(guān)聯(lián)掩碼,是一個DWORD_PTR類型的值,長度為8個字節(jié)(64位),每個bit代表一個CPU核心。例如,要將線程綁定到第0個核心,則dwThreadAffinityMask = 0B_0001(0x01);綁定到第1個核心,則dwThreadAffinityMask = 0B_0010(0x02);綁定到第2個核心,則dwThreadAffinityMask = 0B_0100(0x04);綁定到第3個核心,則dwThreadAffinityMask = 0B_1000(0x08)。如果要綁定到多個核心,比如第1和第2個核心,則dwThreadAffinityMask = 0B_0110,對應(yīng)的十六進(jìn)制數(shù)為0x06。

調(diào)用示例首先需要引入Win32 API:

[DllImport("kernel32.dll")]static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);[DllImport("kernel32.dll")]static extern IntPtr GetCurrentThread();

由于dwThreadAffinityMask的值是按照2的n次冪遞增,與通常習(xí)慣指定第n個核心不符,并且不同設(shè)備的CPU核心數(shù)不一樣,指定CPU核心時可能超出CPU核心數(shù)量,因此可以對指定CPU核心做簡單的處理:

static ulong SetCpuID(int lpIdx){    ulong cpuLogicalProcessorId = 0;    if (lpIdx >= System.Environment.ProcessorCount)    {        lpIdx = 0;    }    //通過移位運算轉(zhuǎn)換lpIdx->dwThreadAffinityMask:0->1,1->2,2->4,3->8,……    cpuLogicalProcessorId |= 1UL << lpIdx;    return cpuLogicalProcessorId;}

接下來可以進(jìn)行測試:

ulong LpId = SetCpuID((int)lpIdx);SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(LpId));Stopwatch stopwatch = new Stopwatch();stopwatch.Start();for (int i = 0; i < 100000000; i++){    // 執(zhí)行一些操作}stopwatch.Stop();Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + " ms");

效果如圖所示:

Windows下綁定線程到指定的CPU核心

SetProcessAffinityMask函數(shù)與SetThreadAffinityMask非常相似,不同之處在于其作用于整個進(jìn)程,可以決定進(jìn)程內(nèi)的所有線程共同運行在指定的處理器上。其函數(shù)定義如下:

BOOL SetProcessAffinityMask(  [in] HANDLE    hProcess,  [in] DWORD_PTR dwProcessAffinityMask);

和SetThreadAffinityMask一樣,也需要傳遞兩個參數(shù),只不過第一個參數(shù)傳遞的是進(jìn)程的句柄。

總結(jié):在某些場景下,可以通過SetThreadAffinityMask和SetProcessAffinityMask提高程序執(zhí)行效率,主要基于以下幾個原因:

  • 提高性能:通過將線程綁定到特定的處理器,可以減少線程在不同處理器之間的切換開銷,尤其是在多核系統(tǒng)中,有助于提升程序的執(zhí)行效率。
  • 避免緩存抖動:確保線程始終在同一個處理器上運行,可以減少緩存未命中,因為相關(guān)的數(shù)據(jù)更可能保留在該處理器的高速緩存中。
  • 實時系統(tǒng)和并發(fā)控制:在需要嚴(yán)格控制線程執(zhí)行位置的場景下,比如實時系統(tǒng)或者某些并發(fā)控制策略中,通過設(shè)定處理器關(guān)聯(lián)可以滿足特定的調(diào)度需求。

需要注意的是,SetThreadAffinityMask和SetProcessAffinityMask并不是獨占CPU核心,如果關(guān)聯(lián)的CPU核心本身負(fù)載就很高,這個時候程序執(zhí)行效率反而會降低。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊14 分享