簡體   English   中英

如何使用 C++11 std::thread 設置堆棧大小

[英]How to set the stacksize with C++11 std::thread

我一直在嘗試熟悉 C++11 中的std::thread庫,但遇到了絆腳石。

最初我來自 posix 線程背景,想知道如何在構造之前設置 std::thread 的堆棧大小,因為我似乎找不到執行此類任務的任何參考。

使用 pthreads 設置堆棧大小是這樣完成的:

void* foo(void* arg);
.
.
.
.
pthread_attr_t attribute;
pthread_t thread;

pthread_attr_init(&attribute);
pthread_attr_setstacksize(&attribute,1024);
pthread_create(&thread,&attribute,foo,0);
pthread_join(thread,0);

使用std::thread時是否有類似的東西?

我一直在使用以下參考資料:

http://en.cppreference.com/w/cpp/thread

最初我來自 posix 線程背景,想知道如何在構造之前設置 std::thread 的堆棧大小,因為我似乎找不到執行此類任務的任何參考。

你不能。 std::thread不支持這一點,因為std::thread是標准化的,並且 C++ 不要求機器甚至有堆棧,更不用說固定大小的了。

pthreads 在它們支持的硬件方面有更多的限制,並且它假設每個線程有一些固定的堆棧大小。 (所以你可以配置這個)

正如 Loki Astari 已經說過的那樣,實際需要非默認堆棧大小的情況極為罕見,通常是錯誤或錯誤編碼的結果。

  • 如果您覺得默認的堆棧大小對您的需求來說太大了並且想減少它,那就忘記它吧。 每個現代操作系統現在都使用虛擬內存/按需提交,這意味着在您訪問頁面之前,內存只是保留的,而不是實際分配的。 減少堆棧大小不會減少您的實際內存占用。

  • 由於這種行為,操作系統可以將默認堆棧大小設置為非常大的值。 例如,在 vanilla Debian 上,這是 8MB ( ulimit -s ),這應該足以滿足所有需要。 如果你仍然設法達到那個限制,我的第一個想法是你的代碼是錯誤的,所以你應該首先檢查它並將東西移到堆中,將遞歸函數轉換為循環等。

  • 如果盡管如此你真的真的需要改變堆棧大小(即增加它,因為減少它是沒有用的),在 POSIX 上你總是可以在程序開始時使用setrlimit來增加默認堆棧大小。 當然這會影響所有線程,但只有需要它的線程才會真正使用額外的內存。

  • 最后但同樣重要的是,平心而論,我可以看到一個極端情況,其中減少堆棧大小是有意義的:如果您在 32 位系統上有大量線程,它們可能會耗盡您的虛擬地址空間(同樣,不是實際內存消耗)直到您沒有足夠的地址空間可用於堆。 同樣, setrlimit是你的朋友,盡管我建議遷移到 64 位系統以從更大的虛擬地址空間中受益(如果你的程序無論如何都那么大,你可能也會從額外的 RAM 中受益)。

我也一直在研究這個問題。 對於某些應用程序,默認堆棧大小是不夠的。 示例:程序根據它正在解決的具體問題進行深度遞歸; 該程序需要創建許多線程,內存消耗是一個問題。

以下是我發現的(部分)解決方案/解決方法的摘要:

  • g++ 在 Linux 上支持-fsplit-stack選項。 有關拆分堆棧的更多信息,請參見 以下是他們網站的摘要:

拆分堆棧的目標是允許根據需要自動增長的不連續堆棧。 這意味着您可以運行多個線程,每個線程都從一個小堆棧開始,並讓堆棧根據程序的需要增長和收縮。

備注: -fsplit-stack僅在我開始使用gold linker后才對我有用。 似乎 clang++ 也會支持這個標志。 嘗試使用標志-fsplit-stack編譯我的應用程序時,我嘗試的版本 (clang++ 3.3) 崩潰了。

  • 在 Linux 上,通過在啟動應用程序之前執行ulimit -s <size>來設置堆棧大小。 size是以 Kbs 為單位的堆棧大小。 備注:命令unlimit -s unlimited不會影響使用std::thread創建的線程的大小。 當我使用ulimit -s unlimited時,主線程可以增長,但使用std::thread創建的線程具有默認大小。

  • 在使用 Visual Studio 的 Windows 上,我們可以在模塊定義文件中使用鏈接器/STACK參數或/STACKSIZE ,這是所有已創建線程的默認大小。 有關詳細信息,請參閱此鏈接 我們還可以使用命令行工具EDITBIN在任何可執行文件中修改此參數。

  • 在使用 mingw g++ 的 Windows 上,我們可以使用選項-Wl,--stack,<size> 出於某種原因,當使用 cygwin g++ 時,這個標志只影響主線程的大小。

不起作用的方法:

  • ulimit -s <size>在 OSX 上。 它只影響主線程的大小。 此外,Mac OSX 默認的 pthread 棧大小是 512kB。

  • setrlimit僅影響 Linux 和 OSX 上主線程的大小。 在 cygwin 上,它對我來說從來沒有用過,它似乎總是返回錯誤。

對於 OSX,唯一的選擇似乎是使用boost::thread而不是std::thread ,但如果我們想堅持標准,這就不好了。 我希望 g++ 和 clang++ 將來也能支持 OSX 上的-fsplit-stack

我在 Scott Meyers Overview of the New C++(C++0x)一書中找到了這個,因為它太長了我不能將它作為評論發布,這有幫助嗎?

還有一個標准 API 用於獲取線程、互斥體、條件變量等背后的特定於平台的句柄。這些句柄被假定為設置線程優先級、設置堆棧大小等的機制。(關於設置堆棧大小, Anthony Williams 指出:“在那些支持設置堆棧大小的操作系統中,它們的做法各不相同。如果您正在為特定平台編寫代碼(這樣使用 native_handle 就可以了),那么您可以使用該平台的工具來切換堆棧。例如,在 POSIX 上,您可以使用 makecontext 和 swapcontext 以及堆棧的顯式分配,而在 Windows 上,您可以使用 Fibers。然后您可以使用特定於平台的工具(例如鏈接器標志)將默認堆棧大小設置為某個值真的很小,然后在必要時將堆棧切換到更大的東西。”)

剛才自己正在尋找這個問題的答案。

看起來雖然 std::thread 不支持這個,但 boost::thread 支持。

特別是,您可以使用boost::thread::attributes來完成此操作:

boost::thread::attributes attrs;
attrs.set_stack_size(4096*10);
boost::thread myThread(attrs, fooFunction, 42);

如果你不想包含一個大庫,你可以像這樣做一些修改。

它仍然是依賴於 C++ 編譯器的 STL 庫。 (現在是 Clang / MSVC)

黑客STL庫

std::thread thread = std::stacking_thread(65536, []{
    printf("Hello, world!\n"); 
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM