Linux下pthread的執行緒親和性研究

2021-09-23 18:39:57 字數 3802 閱讀 8534

linux下pthread的執行緒親和性研究

追夢的小鳥

一、什麼是執行緒的親和性:

了解 linux2.6 排程器如何處理 cpu 親和性(affinity)可以幫助您更好地設計

使用者空間的應用程式。

軟親和性 意味著程序並不會在處理器之間頻繁遷移,而

硬親和性 則意味著程序需要在您指定的處理器上執行。

簡單地說,cpu 親和性(affinity) 就是

程序要在某個給定的 cpu 上盡量長時間地執行而不被遷移到其他處理器的傾向性。

linux 核心程序排程器天生就具有被稱為 軟 cpu 親和性(affinity) 的特性,這意味著程序通常不會在處理器之間頻繁遷移。這種狀態正是我們希望的,因為程序遷移的頻率小就意味著產生的負載小。

2.6 版本的 linux 核心還包含了一種機制,它讓開發人員可以程式設計實現 硬 cpu 親和性(affinity)。這意味著

應用程式可以顯式地指定程序在哪個(或哪些)處理器上執行。

在 linux 核心中,所有的程序都有乙個相關的資料結構,稱為

task_struct。這個結構非常重要,原因有很多;其中與 親和性(affinity)相關度最高的是

cpus_allowed 位掩碼。

這個位掩碼由 n 位組成,與系統中的 n 個邏輯處理器一一對應。 具有 4 個物理 cpu 的系統可以有 4 位。如果這些 cpu 都啟用了超執行緒,那麼這個系統就有乙個 8 位的位掩碼。

如果為給定的程序設定了給定的位,那麼這個程序就可以在相關的 cpu 上執行。因此,如果乙個程序可以在任何 cpu 上執行,並且能夠根據需要在處理器之間進行遷移,那麼位掩碼就全是 1。實際上,這就是 linux 中程序的

預設狀態。

linux 核心 api 提供了一些方法,讓使用者可以修改位掩碼或檢視當前的位掩碼:

二、為什麼應該使用硬親和性(affinity)?

通常 linux 核心都可以很好地對程序進行排程,在應該執行的地方執行程序(這就是說,在可用的處理器上執行並獲得很好的整體效能)。核心包含了一些用來檢測 cpu 之間任務負載遷移的演算法,可以啟用程序遷移來降低繁忙的處理器的壓力。

一般情況下,在應用程式中只需使用預設的排程器行為。然而,您可能會希望修改這些預設行為以實現效能的優化。讓我們來看一下使用硬親和性(affinity) 的 3 個原因。

原因 1. 有大量計算要做

基於大量計算的情形通常出現在科學和理論計算中,但是通用領域的計算也可能出現這種情況。乙個常見的標誌是您發現自己的應用程式要在多處理器的機器上花費大量的計算時間。

原因 2. 您在測試複雜的應用程式

測試複雜軟體是我們對核心的親和性(affinity)技術感興趣的另外乙個原因。考慮乙個需要進行線性可伸縮性測試的應用程式。有些產品宣告可以在 使用更多硬體 時執行得更好。

我們不用購買多台機器(為每種處理器配置都購買一台機器),而是可以:

如果應用程式隨著 cpu 的增加可以線性地伸縮,那麼每秒事務數和 cpu 個數之間應該會是線性的關係(例如斜線圖 —— 請參閱下一節的內容)。這樣建模可以確定應用程式是否可以有效地使用底層硬體。

amdahl 法則

t(1)

s = ------

t(j)

其中t(j)是在使用j個處理器執行程式時所花費的時間。

amdahl 法則說明這種加速比在現實中可能並不會發生,但是可以非常接近於該值。對於通常情況來說,我們可以推論出每個程式都有一些序列的元件。隨著問題集不斷變大,序列元件最終會在優化解決方案時間方面達到乙個上限。

amdahl 法則在希望保持高 cpu 快取命中率時尤其重要。如果乙個給定的程序遷移到其他地方去了,那麼它就失去了利用 cpu 快取的優勢。實際上,如果正在使用的 cpu 需要為自己快取一些特殊的資料,那麼所有其他 cpu 都會使這些資料在自己的快取中失效。

因此,如果有多個執行緒都需要相同的資料,那麼將這些執行緒繫結到乙個特定的 cpu 上是非常有意義的,這樣就確保它們可以訪問相同的快取資料(或者至少可以提高快取的命中率)。否則,這些執行緒可能會在不同的 cpu 上執行,這樣會頻繁地使其他快取項失效。

原因 3. 您正在執行時間敏感的、決定性的程序

我們對 cpu 親和性(affinity)感興趣的最後乙個原因是實時(對時間敏感的)程序。例如,您可能會希望使用硬親和性(affinity)來指定乙個 8 路主機上的某個處理器,而同時允許其他 7 個處理器處理所有普通的系統排程。這種做法確保長時間執行、對時間敏感的應用程式可以得到執行,同時可以允許其他應用程式獨佔其餘的計算資源。

三、程式設計實現硬親和性:

glibc版本:2.5.12

#include

#include

#include

int getcpucount()

void *thread_fun()

return null;

}

int main()

__cpu_zero(&cpu_info);

__cpu_set(

1, &cpu_info);

if (0!=pthread_attr_setaffinity_np(&attr2, sizeof(cpu_set_t), &cpu_info))

if (0!=

pthread_create(&t1, &attr1, thread_fun, null))

if (0!=pthread_create(&t2, &attr2, thread_fun, null))

pthread_join(t1, null);

pthread_join(t2, null);

}

備:同樣也可以使用函式

pthread_setaffinity_np函式來替代pthread_attr_setaffinity_np,即:

將if (0!=

pthread_attr_setaffinity_np(&attr1, sizeof(cpu_set_t), &cpu_info))

替換為;

if (0!=

pthread_setaffinity_np(t1, sizeof(cpu_set_t), &cpu_info))

同時,pthread_setaffinity_np需放在

pthread_create後面;

詳細**如下:

#include

#include

#include

int getcpucount()

void *thread_fun()

return null;

}

int main()

if (0!=pthread_create(&t2, &attr2, thread_fun, null))

cpu_set_t cpu_info;

__cpu_zero(&cpu_info);

__cpu_set(0, &cpu_info);

if (0!=

pthread_setaffinity_np(t1, sizeof(cpu_set_t), &cpu_info))

__cpu_zero(&cpu_info);

__cpu_set(1, &cpu_info);

if (0!=pthread_setaffinity_np(t2, sizeof(cpu_set_t), &cpu_info))

pthread_join(t1, null);

pthread_join(t2, null);

}

編譯命令:gcc -o thread_affinity thread_affinity.c -lpthread

在windows下配置pthread多執行緒

pthread是由posix提出的一套通用的執行緒庫,在linux平台下,它被廣泛的支援,而windows平台下,卻並不被支援,而pthreads w32為我們提供了解決方案,本文我們準備在我們的windows平台下進行pthread w32的安裝,在網路上有類似的文章,但是講的都是比較老的平台,在...

linux下pthread的編譯

今天在linux下寫乙個多執行緒程式時,在.c 檔案中包含了標頭檔案 pthread.h 但是編譯時卻報錯 對 pthread create 未定義的引用 上網查了下,原來pthread庫不是linux預設的庫,所以在編譯時要手動鏈結,做法如下 gcc mian.c lpthread find pa...

linux下pthread的編譯詳解

今天在linux下寫乙個多執行緒程式時,在.c 檔案中包含了標頭檔案 pthread.h 但是編譯時卻報錯 對 pthread create 未定義的引用 gcc mian.c lpthread 由於我是在clion下寫的 所以要想讓clion支援自動鏈結pthread庫,需要在專案的cmakeli...