C ++绿色线程的堆栈分配

我在C ++绿色线程中进行了一些研究,主要是boost::coroutine2和类似的POSIX函数,如makecontext()/swapcontext() ,并计划在boost::coroutine2之上实现一个C ++绿色线程库。 两者都需要用户代码为每个新函数/协程分配一个堆栈。

我的目标平台是x64 / Linux。 我希望我的绿色线程库适合一般用途,所以堆栈应该根据需要进行扩展(合理的上限是很好的,例如10MB),如果堆栈可能缩小,因为太多的内存不用(不是必需的)。 我还没有想出一个合适的算法来分配堆栈。

经过一些Google搜索之后,我自己想出了一些选择:

  • 使用由编译器实现的拆分堆栈(gcc -fsplit-stack),但拆分堆栈具有性能开销。 由于性能原因,Go已经从分离堆栈移开。
  • mmap()分配一大块内存,希望内核足够聪明,可以在物理内存未分配的情况下分配,只有在访问堆栈时才分配内存。 在这种情况下,我们处于内核的摆布之中。
  • 使用mmap(PROT_NONE)预留大量内存空间并设置SIGSEGV信号处理程序。 在信号处理程序中,当SIGSEGV由堆栈访问引起(被访问的内存在预留的大内存空间内)时,使用mmap(PROT_READ | PROT_WRITE)分配所需的内存。 这是这种方法的问题: mmap()不是异步安全的,不能在信号处理程序中调用。 它仍然可以实现,但非常棘手:在程序启动期间为存储器分配创建另一个线程,并使用pipe() + read()/write()从信号处理程序向线程发送内存分配信息。
  • 关于选项3的几个问题:

  • 我不确定这种方法的性能开销,当内存空间由于数千次mmap()调用而极度分散时,内核/ CPU的性能如何?
  • 如果在内核空间访问未分配的内存,此方法是否正确? 例如,当read()被调用时?
  • 是否有任何其他(更好)的绿色线程堆栈分配选项? 在其他实现中如何分配绿色线程堆栈,例如Go / Java?


    glibc为普通C程序分配堆栈的方式是使用为此目的而设计的以下mmap标志来映射区域:

       MAP_GROWSDOWN
              Used for stacks.  Indicates to the kernel virtual memory  system
              that the mapping should extend downward in memory.
    

    为了兼容性,你也应该使用MAP_STACK 。 然后你不必自己编写SIGSEGV处理程序,堆栈会自动增长。 可以像这里描述的那样设置边界“ulimit -s unlimited”是做什么的?

    如果你想要一个有限的堆栈大小,这通常是人们为信号处理程序而做的,如果他们想要调用sigaltstack(2) ,就发出一个普通的mmap调用。

    Linux内核总是映射支持虚拟页面的物理页面,当页面首次访问时(可能不是实时内核,但当然是所有其他配置)捕获页面错误。 如果您有兴趣,可以使用/proc/<pid>/pagemap界面(或者我写的https://github.com/dwks/pagemap)来验证这一点。


    为什么选择mmap? 当你使用new(或malloc)分配内存时,内存不变,而且绝对没有映射。

    const int STACK_SIZE = 10 * 1024*1024;
    char*p = new char[STACK_SIZE*numThreads];
    

    p现在有足够的内存供你想要的线程使用。 当你需要内存时,开始访问p + STACK_SIZE * i

    链接地址: http://www.djcxy.com/p/53189.html

    上一篇: Stack allocation for C++ green threads

    下一篇: How to implement Coroutines on iOS