简体   繁体   English

如何使用 C++11 std::thread 设置堆栈大小

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

I've been trying to familiarize myself with the std::thread library in C++11, and have arrived at a stumbling block.我一直在尝试熟悉 C++11 中的std::thread库,但遇到了绊脚石。

Initially I come from a posix threads background, and was wondering how does one setup the stack size of the std::thread prior to construction, as I can't seem to find any references to performing such a task.最初我来自 posix 线程背景,想知道如何在构造之前设置 std::thread 的堆栈大小,因为我似乎找不到执行此类任务的任何参考。

Using pthreads setting the stack size is done like this:使用 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);

Is there something similar when using std::thread ?使用std::thread时是否有类似的东西?

I've been using the following reference:我一直在使用以下参考资料:

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

Initially I come from a posix threads background, and was wondering how does one setup the stack size of the std::thread prior to construction, as I can't seem to find any references to performing such a task.最初我来自 posix 线程背景,想知道如何在构造之前设置 std::thread 的堆栈大小,因为我似乎找不到执行此类任务的任何参考。

You can't.你不能。 std::thread doesn't support this because std::thread is standardized, and C++ does not require that a machine even has a stack, much less a fixed-size one. std::thread不支持这一点,因为std::thread是标准化的,并且 C++ 不要求机器甚至有堆栈,更不用说固定大小的了。

pthreads are more restrictive in terms of the hardware that they support, and it assumes that there is some fixed stack size per thread. pthreads 在它们支持的硬件方面有更多的限制,并且它假设每个线程有一些固定的堆栈大小。 (So you can configure this) (所以你可以配置这个)

As Loki Astari already said, it is extremely rare to actually need a non-default stack-size and usually either a mistake or the result of bad coding.正如 Loki Astari 已经说过的那样,实际需要非默认堆栈大小的情况极为罕见,通常是错误或错误编码的结果。

  • If you feel like the default stack size is too big for your needs and want to reduce it, just forget about it.如果您觉得默认的堆栈大小对您的需求来说太大了并且想减少它,那就忘记它吧。 Every modern OS now uses virtual memory / on-demand commit, which means that memory is only reserved, not actually allocated, until you access the pages.每个现代操作系统现在都使用虚拟内存/按需提交,这意味着在您访问页面之前,内存只是保留的,而不是实际分配的。 Reducing the stack size will not reduce your actual memory footprint.减少堆栈大小不会减少您的实际内存占用。

  • Due to this very behaviour, OSes can afford to set the default stack size to very big values.由于这种行为,操作系统可以将默认堆栈大小设置为非常大的值。 Eg on a vanilla Debian this is 8MB ( ulimit -s ) which should be enough for every need.例如,在 vanilla Debian 上,这是 8MB ( ulimit -s ),这应该足以满足所有需要。 If you still manage to hit that limit, my first idea would be that your code is wrong, so you should first and foremost review it and move things to the heap, transform recursive functions into loops, etc.如果你仍然设法达到那个限制,我的第一个想法是你的代码是错误的,所以你应该首先检查它并将东西移到堆中,将递归函数转换为循环等。

  • If despite all of this you really really need to change the stack size (ie increase it, since reducing it is useless), on POSIX you can always use setrlimit at the start of your program to increase the default stack size.如果尽管如此你真的真的需要改变堆栈大小(即增加它,因为减少它是没有用的),在 POSIX 上你总是可以在程序开始时使用setrlimit来增加默认堆栈大小。 Sure this will affect all threads, but only the ones who need it will actually use the additional memory.当然这会影响所有线程,但只有需要它的线程才会真正使用额外的内存。

  • Last but not least, in all fairness I can see a corner case where reducing the stack size would make sense: if you have tons of threads on a 32 bits system, they could eat up your virtual address space (again, not the actual memory consumption) up to the point that you don't have enough address space available for the heap.最后但同样重要的是,平心而论,我可以看到一个极端情况,其中减少堆栈大小是有意义的:如果您在 32 位系统上有大量线程,它们可能会耗尽您的虚拟地址空间(同样,不是实际内存消耗)直到您没有足够的地址空间可用于堆。 Again, setrlimit is your friend here even though I'd advise to move to a 64 bits system to benefit from the larger virtual address space (and if your program is that big anyway, you'll probably benefit from the additional RAM too).同样, setrlimit是你的朋友,尽管我建议迁移到 64 位系统以从更大的虚拟地址空间中受益(如果你的程序无论如何都那么大,你可能也会从额外的 RAM 中受益)。

I have also been investigating this issue.我也一直在研究这个问题。 For some applications, the default stack size is not adequate.对于某些应用程序,默认堆栈大小是不够的。 Examples: the program does deep recursion dependent on the specific problem it is solving;示例:程序根据它正在解决的具体问题进行深度递归; the program needs to create many threads and memory consumption is an issue.该程序需要创建许多线程,内存消耗是一个问题。

Here is a summary of (partial) solutions / workarounds I found:以下是我发现的(部分)解决方案/解决方法的摘要:

  • g++ supports a -fsplit-stack option on Linux. g++ 在 Linux 上支持-fsplit-stack选项。 See for more information about Split stacks.有关拆分堆栈的更多信息,请参见 Here is summary from their website:以下是他们网站的摘要:

The goal of split stacks is to permit a discontiguous stack which is grown automatically as needed.拆分堆栈的目标是允许根据需要自动增长的不连续堆栈。 This means that you can run multiple threads, each starting with a small stack, and have the stack grow and shrink as required by the program.这意味着您可以运行多个线程,每个线程都从一个小堆栈开始,并让堆栈根据程序的需要增长和收缩。

Remark: -fsplit-stack only worked for me after I started using the gold linker .备注: -fsplit-stack仅在我开始使用gold linker后才对我有用。 It seems clang++ will also support this flag.似乎 clang++ 也会支持这个标志。 The version I tried (clang++ 3.3) crashed when trying to compile my application using the flag -fsplit-stack .尝试使用标志-fsplit-stack编译我的应用程序时,我尝试的版本 (clang++ 3.3) 崩溃了。

  • On Linux, set the stack size by executing ulimit -s <size> before starting your application.在 Linux 上,通过在启动应用程序之前执行ulimit -s <size>来设置堆栈大小。 size is the stack size in Kbs. size是以 Kbs 为单位的堆栈大小。 Remark: the command unlimit -s unlimited did not affect the size of threads created with std::thread .备注:命令unlimit -s unlimited不会影响使用std::thread创建的线程的大小。 When I used ulimit -s unlimited , the main thread could grow, but the threads created with std::thread had the default size.当我使用ulimit -s unlimited时,主线程可以增长,但使用std::thread创建的线程具有默认大小。

  • On Windows using Visual Studio, we can use use the linker /STACK parameter or /STACKSIZE in the module definition file, this is the default size for all created threads.在使用 Visual Studio 的 Windows 上,我们可以在模块定义文件中使用链接器/STACK参数或/STACKSIZE ,这是所有已创建线程的默认大小。 See this link for more information.有关详细信息,请参阅此链接 We can also modify this parameter in any executable using the command line tool EDITBIN .我们还可以使用命令行工具EDITBIN在任何可执行文件中修改此参数。

  • On Windows using mingw g++, we can use the option -Wl,--stack,<size> .在使用 mingw g++ 的 Windows 上,我们可以使用选项-Wl,--stack,<size> For some reason, when using cygwin g++, this flag only affects the size of the main thread.出于某种原因,当使用 cygwin g++ 时,这个标志只影响主线程的大小。

Approaches that did not work for me:不起作用的方法:

  • ulimit -s <size> on OSX. ulimit -s <size>在 OSX 上。 It affects only the size of the main thread.它只影响主线程的大小。 Moreover, the Mac OSX default for a pthread stack size is 512kB.此外,Mac OSX 默认的 pthread 栈大小是 512kB。

  • setrlimit only affects the size of the main thread on Linux and OSX. setrlimit仅影响 Linux 和 OSX 上主线程的大小。 On cygwin, it never worked for me, it seems it always returns an error.在 cygwin 上,它对我来说从来没有用过,它似乎总是返回错误。

For OSX, the only alternative seems to use boost::thread instead of std::thread , but this is not nice if we want to stick with the standard.对于 OSX,唯一的选择似乎是使用boost::thread而不是std::thread ,但如果我们想坚持标准,这就不好了。 I hope g++ and clang++ will also support -fsplit-stack on OSX in the future.我希望 g++ 和 clang++ 将来也能支持 OSX 上的-fsplit-stack

I found this in Scott Meyers book Overview of the New C++(C++0x) , as it's quite long I can't post it as a comment, is this helpful?我在 Scott Meyers Overview of the New C++(C++0x)一书中找到了这个,因为它太长了我不能将它作为评论发布,这有帮助吗?

There is also a standard API for getting at the platform-specific handles behind threads, mutexes, condition variables, etc.. These handles are assumed to be the mechanism for setting thread priorities, setting stack sizes, etc. (Regarding setting stack sizes, Anthony Williams notes: "Of those OSs that support setting the stack size, they all do it differently. If you're coding for a specify platform (such that use of the native_handle would be OK), then you could use that platform's facilities to switch stacks. eg on POSIX you could use makecontext and swapcontext along with explicit allocation of a stack, and on Windows you could use Fibers. You could then use the platform-specific facilities (eg Linker flags) to set the default stack size to something really tiny, and then switch stacks to something bigger where necessary.“)还有一个标准 API 用于获取线程、互斥体、条件变量等背后的特定于平台的句柄。这些句柄被假定为设置线程优先级、设置堆栈大小等的机制。(关于设置堆栈大小, Anthony Williams 指出:“在那些支持设置堆栈大小的操作系统中,它们的做法各不相同。如果您正在为特定平台编写代码(这样使用 native_handle 就可以了),那么您可以使用该平台的工具来切换堆栈。例如,在 POSIX 上,您可以使用 makecontext 和 swapcontext 以及堆栈的显式分配,而在 Windows 上,您可以使用 Fibers。然后您可以使用特定于平台的工具(例如链接器标志)将默认堆栈大小设置为某个值真的很小,然后在必要时将堆栈切换到更大的东西。”)

Was looking for the answer to this myself just now.刚才自己正在寻找这个问题的答案。

It appears that while std::thread does not support this, boost::thread does.看起来虽然 std::thread 不支持这个,但 boost::thread 支持。

In particular, you can use boost::thread::attributes to accomplish this:特别是,您可以使用boost::thread::attributes来完成此操作:

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

You can do some modifications like this if you don't want to include a big library.如果你不想包含一个大库,你可以像这样做一些修改。

It is still dependend C++ compiler STL library.它仍然是依赖于 C++ 编译器的 STL 库。 (Clang / MSVC now) (现在是 Clang / MSVC)

HackingSTL Library黑客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