繁体   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