2011-04-19 45 views
6

我正在爲在嵌入式Linux系統中運行的實時程序編寫代碼。由於重要的一點是我們不會在頁面錯誤上出現無法預料的停頓,所以我想在堆棧中進行默認設置,以確保我們使用的區域能夠被mlockall()調用覆蓋。對於pthreads線程,棧中的prefault的最佳方式是什麼?

對於主線程,這很簡單;只需做幾個大的alloca(),並確保每隔幾頁寫一次。這是可行的,因爲在程序啓動時,堆棧限制遠大於我們需要的數量;我們最終分配的是我們預設的錯誤數量。

但是,對於pthread堆棧,它們是否也將使用MAP_GROWSDOWN進行分配?如果是這樣,什麼是在預先測他們考慮,最好的辦法:

  1. 我們不知道有多少(已知)堆棧的大小是由libc的啓動消耗
  2. 我們不想分配更多的內存堆棧比是必要的

我知道,我可以使用pthread_attr_setstack在手動分配的堆棧傳遞,但這種複雜的線程清理後,所以我寧願避免這種情況如果可能的話。

因此,執行此預設的最佳方法是什麼?如果有一個簡單的方法來找出堆棧的下界(就在守衛頁面上方)就足夠了;在這一點上,我可以簡單地寫入每個頁面,從那裏到當前的堆棧指針。

請注意,便攜性不是一個問題;我們很高興能有一種只能在x86-32和Linux下運行的解決方案。

回答

3

如果您使用pthread_attr_setstacksize,仍可以使用已知大小自動分配。

glibc nptl在堆棧之間留下警戒頁面,因此您還可以設置一個SEGV處理程序,直到出錯爲止,然後將longjmp排除在外。那會很醜陋!

編輯:一個非常不便的方法是打開/proc/self/maps找到你的堆棧!

+0

API合同中是否有保證pthread_attr_setstacksize不會使用與GROWSDOWN類似的東西,即,mlockall()會在分配時立即應用於整個堆棧,而無需額外的預先設定? – bdonlan 2011-04-19 19:55:15

+0

線程堆棧都以glibc nptl爲界。我不知道如果這是規範的一部分,但我懷疑它是。快速查看顯示nptl也使用堆棧池,因此如果您創建/銷燬線程,那麼如果您獲得「熱」堆棧,您的代碼不應該失敗。 – 2011-04-19 20:01:04

+0

好吧,我想現在對我們來說足夠好了 - 希望我們不會陷入pageins阻止的情況:) – bdonlan 2011-04-19 20:40:14

1

是的。如果在pthread_create之前調用了mlockall(MCL_CURRENT | MCL_FUTURE),則線程堆棧的頁面錯誤將在啓動線程時發生。之後,在線程中訪問堆棧時將不會再出現頁面錯誤。 所以人們總是爲新創建的線程設置合適的線程大小,以避免爲將來的線程鎖定太多的內存。 看看: https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example

如果你改變了線程堆棧大小7MB,您將看到: 初始計數:頁面錯誤,專業:0(允許> = 0),輔修:190(允許> = 0 ) mlockall()generated:Pagefaults,Major:0(Allowed> = 0),Minor:393(Allowed> = 0) malloc()和touch generated:Pagefaults,Major:0(允許> = 0) 25633(允許> = 0) 第二個malloc()和使用生成的:Pagefaults,Major:0(允許0),Minor:0(允許0)

看看ps -leyf的輸出, RSS現在約100 [MB] 按退出 我是一個帶有堆棧的RT線程,在使用過程中不會產生頁面錯誤,stacksize = 7340032 由創建線程引起:Pagefaults,Major:0(允許> = 0),Minor:1797(允許> = 0) 使用線程堆棧導致:Pagefaults,Major:0(允許0),Minor:0(允許0)

1797創建線程時發生頁面故障,大約7MB。 -barry

相關問題