【发布时间】:2016-05-09 11:23:03
【问题描述】:
我正在研究 C++ 绿色线程,主要是 boost::coroutine2 和类似的 POSIX 函数,如 makecontext()/swapcontext(),并计划在 boost::coroutine2 之上实现 C++ 绿色线程库。两者都需要用户代码为每个新函数/协程分配一个堆栈。
我的目标平台是 x64/Linux。我希望我的绿色线程库适合一般用途,因此堆栈应根据需要扩展(合理的上限很好,例如 10MB),如果未使用太多内存时堆栈可以收缩(不需要),那就太好了)。我还没有找到合适的算法来分配堆栈。
经过一番谷歌搜索,我自己想出了几个选项:
- 使用编译器实现的拆分堆栈(gcc -fsplit-stack),但拆分堆栈有性能开销。由于性能原因,Go 已经放弃了拆分堆栈。
- 用
mmap()分配一大块内存希望内核足够聪明,让物理内存保持未分配状态,仅在访问堆栈时分配。在这种情况下,我们受内核的支配。 - 使用
mmap(PROT_NONE)保留一个大内存空间并设置SIGSEGV信号处理程序。在信号处理程序中,当SIGSEGV是由堆栈访问引起时(访问的内存在预留的大内存空间内),用mmap(PROT_READ | PROT_WRITE)分配需要的内存。这是这种方法的问题:mmap()不是异步安全的,不能在信号处理程序中调用。它仍然可以实现,非常棘手:在程序启动期间创建另一个线程用于内存分配,并使用pipe() + read()/write()将内存分配信息从信号处理程序发送到线程。
关于选项 3 的更多问题:
- 我不确定这种方法的性能开销,当内存空间由于数千个
mmap()调用而极度碎片化时,内核/CPU 的性能如何? - 如果在内核空间中访问未分配的内存,这种方法是否正确?例如何时调用
read()?
对于绿色线程的堆栈分配还有其他(更好的)选项吗?在其他实现中如何分配绿色线程堆栈,例如围棋/Java?
【问题讨论】:
-
虽然根据 POSIX,
mmap不是异步安全的,但它实际上在 Linux 和几乎所有合理、可用的 UNIX 变体中都是异步安全的。 -
@ChrisDodd 我能问一下为什么
mmap对绿色线程有好处吗?我不是专家,但我想知道。 -
@ChrisDodd 我没有找到任何手册页/链接,你介意给我一个链接吗?
-
FWIW,我不知道 Linux 共享内存是否适合您的需求。但是几年前我将它用于谷歌地图应用程序的高性能后端,并且性能非常好。
-
@ErikAlapää 绿色线程都运行在同一个内核线程上,因此它们共享同一个地址空间。 en.wikipedia.org/wiki/Green_threads
标签: c++ memory-management green-threads boost-coroutine