[英]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时是否有类似的东西?
我一直在使用以下参考资料:
最初我来自 posix 线程背景,想知道如何在构造之前设置 std::thread 的堆栈大小,因为我似乎找不到执行此类任务的任何参考。
你不能。 std::thread
不支持这一点,因为std::thread
是标准化的,并且 C++ 不要求机器甚至有堆栈,更不用说固定大小的了。
pthreads 在它们支持的硬件方面有更多的限制,并且它假设每个线程有一些固定的堆栈大小。 (所以你可以配置这个)
正如 Loki Astari 已经说过的那样,实际需要非默认堆栈大小的情况极为罕见,通常是错误或错误编码的结果。
如果您觉得默认的堆栈大小对您的需求来说太大了并且想减少它,那就忘记它吧。 每个现代操作系统现在都使用虚拟内存/按需提交,这意味着在您访问页面之前,内存只是保留的,而不是实际分配的。 减少堆栈大小不会减少您的实际内存占用。
由于这种行为,操作系统可以将默认堆栈大小设置为非常大的值。 例如,在 vanilla Debian 上,这是 8MB ( ulimit -s
),这应该足以满足所有需要。 如果你仍然设法达到那个限制,我的第一个想法是你的代码是错误的,所以你应该首先检查它并将东西移到堆中,将递归函数转换为循环等。
如果尽管如此你真的真的需要改变堆栈大小(即增加它,因为减少它是没有用的),在 POSIX 上你总是可以在程序开始时使用setrlimit来增加默认堆栈大小。 当然这会影响所有线程,但只有需要它的线程才会真正使用额外的内存。
最后但同样重要的是,平心而论,我可以看到一个极端情况,其中减少堆栈大小是有意义的:如果您在 32 位系统上有大量线程,它们可能会耗尽您的虚拟地址空间(同样,不是实际内存消耗)直到您没有足够的地址空间可用于堆。 同样, setrlimit是你的朋友,尽管我建议迁移到 64 位系统以从更大的虚拟地址空间中受益(如果你的程序无论如何都那么大,你可能也会从额外的 RAM 中受益)。
我也一直在研究这个问题。 对于某些应用程序,默认堆栈大小是不够的。 示例:程序根据它正在解决的具体问题进行深度递归; 该程序需要创建许多线程,内存消耗是一个问题。
以下是我发现的(部分)解决方案/解决方法的摘要:
-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)
std::thread thread = std::stacking_thread(65536, []{
printf("Hello, world!\n");
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.