40

我一直在尝试熟悉 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

4

6 回答 6

25

最初我来自 posix 线程背景,并且想知道如何在构造之前设置 std::thread 的堆栈大小,因为我似乎找不到执行此类任务的任何参考。

你不能。std::thread不支持这一点,因为std::thread它是标准化的,C++ 甚至不需要机器有一个堆栈,更不用说固定大小的堆栈了。

pthread 在它们支持的硬件方面更具限制性,并且它假设每个线程有一些固定的堆栈大小。(所以你可以配置这个)

于 2012-12-14T02:27:55.290 回答
19

正如 Loki Astari 已经说过的,实际上需要非默认堆栈大小的情况极为罕见,通常是错误或编码错误的结果。

  • 如果您觉得默认堆栈大小对于您的需求来说太大并且想要减少它,那就忘记它。现在每个现代操作系统都使用虚拟内存/按需提交,这意味着在您访问页面之前,内存只是保留,而不是实际分配。减少堆栈大小不会减少您的实际内存占用。

  • 由于这种行为,操作系统可以将默认堆栈大小设置为非常大的值。例如,在 vanilla Debian 上,这是 8MB ( ulimit -s),应该足以满足所有需要。如果你仍然设法达到这个限制,我的第一个想法是你的代码是错误的,所以你应该首先检查它并将东西移动到堆中,将递归函数转换为循环等。

  • 如果尽管如此,您确实确实需要更改堆栈大小(即增加它,因为减小它是无用的),在 POSIX 上,您始终可以在程序开始时使用setrlimit来增加默认堆栈大小。当然这会影响所有线程,但只有需要它的线程才会真正使用额外的内存。

  • 最后但并非最不重要的一点是,平心而论,我可以看到减少堆栈大小有意义的极端情况:如果您在 32 位系统上有大量线程,它们可能会占用您的虚拟地址空间(同样,不是实际内存消耗)直到您没有足够的地址空间可用于堆。同样,setrlimit在这里是您的朋友,即使我建议迁移到 64 位系统以从更大的虚拟地址空间中受益(如果您的程序无论如何都那么大,您可能也会从额外的 RAM 中受益)。

于 2013-02-14T05:09:58.090 回答
18

我也一直在调查这个问题。对于某些应用程序,默认堆栈大小是不够的。示例:程序根据它正在解决的特定问题进行深度递归;该程序需要创建许多线程并且内存消耗是一个问题。

以下是我发现的(部分)解决方案/解决方法的摘要:

拆分堆栈的目标是允许根据需要自动增长的不连续堆栈。这意味着您可以运行多个线程,每个线程都从一个小堆栈开始,并根据程序的需要让堆栈增长和收缩。

备注:-fsplit-stack仅在我开始使用黄金链接器后才为我工作。似乎 clang++ 也会支持这个标志。尝试使用 flag 编译我的应用程序时,我尝试的版本(clang++ 3.3)崩溃-fsplit-stack

  • ulimit -s <size>在 Linux 上,通过在启动应用程序之前执行来设置堆栈大小。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++ 将来也能-fsplit-stack在 OSX 上支持。

于 2013-12-10T18:47:45.220 回答
16

我在 Scott Meyers 的书中找到了这个Overview of the New C++(C++0x),因为它很长,我不能将它作为评论发布,这有帮助吗?

还有一个标准 API 用于获取线程、互斥体、条件变量等背后的特定于平台的句柄。这些句柄被假定为设置线程优先级、设置堆栈大小等的机制。(关于设置堆栈大小, Anthony Williams 指出:“在那些支持设置堆栈大小的操作系统中,它们的做法都不同。如果您正在为特定平台编码(这样使用 native_handle 就可以了),那么您可以使用该平台的工具来切换堆栈。例如,在 POSIX 上,您可以使用 makecontext 和 swapcontext 以及显式分配堆栈,在 Windows 上,您可以使用 Fibers。然后您可以使用特定于平台的工具(例如链接器标志)将默认堆栈大小设置为某个值真的很小,然后在必要时将堆栈切换到更大的堆栈。“)

于 2012-12-14T02:45:02.723 回答
15

刚才自己也在寻找这个问题的答案。

看来,虽然 std::thread 不支持这一点,但 boost::thread 支持。

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

boost::thread::attributes attrs;
attrs.set_stack_size(4096*10);
boost::thread myThread(attrs, fooFunction, 42);
于 2013-11-09T01:06:52.603 回答
1

如果你不想包含一个大的库,你可以做一些这样的修改。

它仍然是依赖 C++ 编译器 STL 库。(现在是 Clang / MSVC)

HackingSTL 库

std::thread thread = std::stacking_thread(65536, []{
    printf("Hello, world!\n"); 
});
于 2020-11-14T04:40:23.503 回答