【问题标题】:How to set the stacksize with C++11 std::thread如何使用 C++11 std::thread 设置堆栈大小
【发布时间】:2012-12-14 02:17:15
【问题描述】:

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

【问题讨论】:

  • 你可以获得原生处理程序并设置堆栈大小吗? en.cppreference.com/w/cpp/thread/thread/native_handle
  • @billz 创建线程后为时已晚。
  • @Billy:在很多情况下,人们可能希望为线程池创建多个线程,并假设线程所需的所有数据/内存都将在外部,因此可以将堆栈设置为小 - 本质上足以容纳任何电话或代码。
  • @BillyONeal 我正在开发一个需要大量工作线程的程序,这些线程不需要很大的堆栈大小(在 500 kb 堆栈/工作线程上运行它们),标准: :thread 默认堆栈大小为 8 兆字节/线程。如果我想要 10 个工作线程,那就是使用 std::thread 的 80 MB ram,或者使用 pthreads 的 5 MB ram ..
  • @BillyONeal 该死的,看来你是对的,我写了一些 code 来测试它,然后安装了一个最小的 debian 9 amd64,内核为 4.9.110,g++ 6.3.0,和 152 MB ram和 0 交换(这似乎几乎是在不调整 initial ramdisk 的情况下启动的最低 debian 启动 - 介于 140 和 152MB 内存之间)以及模式 1(具有 8MB 堆栈的 std::thread)和模式 2(pthread具有 512 kb 堆栈)能够在失败之前运行 恰好 700 个线程!很酷 - 在启动过程中它需要 ~152 MB,但在启动它的 65MB 内存后,不幸的是

标签: c++ multithreading c++11 pthreads


【解决方案1】:

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

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

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

【讨论】:

  • +1 但这是一个非常令人失望和短视的结果。我至少希望有一个 trait 或堆栈分配器 trait 机制。
  • @ZamfirKerlukson:语言设计者确实考虑到了这一点。您从 Thread 对象获取本机句柄。然后使用适合您平台的本机函数调用对其进行操作。但他们很难做到的原因是这样做通常是一个错误,而真正需要的时候非常/非常罕见。
  • 我看不到如何使用本机句柄更改堆栈大小。有什么提示吗?此外,Mac OSX 默认的 pthread 堆栈大小为 512kB。这是相当小的。
  • 据我所知,您无法在线程启动后更改其堆栈大小。
  • 我喜欢通用软件,它的灵活性为 0。我想知道是否存在没有堆栈的实现?
【解决方案2】:

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

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

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

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

  • 1234563再次,不是实际的内存消耗)直到您没有足够的地址空间可用于堆。同样,setrlimit 是您的朋友,尽管我建议您迁移到 64 位系统以从更大的虚拟地址空间中受益(如果您的程序无论如何都那么大,您可能也会从额外的 RAM 中受益)。

【讨论】:

  • 我在 Linux 和 Cygwin 上尝试了 setrlimit。在 Cygwin 上,它总是失败。在 Linux 上,它只改变主线程的大小。 ulimit -s 解决方案适用于 Linux。在 OSX 上,它只影响主线程的大小。 pthread 堆栈大小的 Mac OS X 默认值为 512kB。这是相当小的。很遗憾,我们无法使用std::thread 更改默认堆栈大小。
  • 过去 640 kb 对每个人来说都足够了
  • ",实际上需要非默认堆栈大小的情况极为罕见"。为自己说话。我使用大型矩阵运算,通常默认堆栈大小是不够的。
  • 在微控制器上,您很可能希望能够设置堆栈大小。只是另一个支持 C++ 不适合微控制器的先入之见的论据。伤心。
  • @Sebastian 我同意能够在微控制器上控制堆栈大小会有所帮助,但我认为在那些环境中使用 RTOS 更为常见,在这种情况下,您将使用 RTOS用于线程操作的 API。 C++ 在那里仍然可行,尽管有些功能不太有用。
【解决方案3】:

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

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

  • g++ 在 Linux 上支持 -fsplit-stack 选项。 See 了解有关拆分堆栈的更多信息。以下是他们网站的摘要:

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

备注:-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,这是所有创建线程的默认大小。有关更多信息,请参阅this link。我们还可以使用命令行工具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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • +1 这是一个有趣的设置堆栈大小的方法。
    • 如果你想在线程启动之前配置它对你没有帮助。
    【解决方案5】:

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

    似乎 std::thread 不支持这一点,但 boost::thread 支持。

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

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

    【讨论】:

      【解决方案6】:

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

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

      HackingSTL Library

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

      【讨论】:

        猜你喜欢
        • 2011-05-18
        • 1970-01-01
        • 2018-02-04
        • 2017-08-28
        • 1970-01-01
        • 1970-01-01
        • 2016-05-20
        • 2014-07-31
        • 1970-01-01
        相关资源
        最近更新 更多