gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 23:21:39 27 4
gpt4 key购买 nike

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

我的目标平台是 x64/Linux。我希望我的绿色线程库适合一般用途,因此堆栈应根据需要扩展(合理的上限很好,例如 10MB),如果未使用太多内存时堆栈可以收缩(不需要),那就太好了)。我还没有找到合适的算法来分配堆栈。

经过一番谷歌搜索,我自己想出了几个选项:

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

关于选项 3 的更多问题:

  1. 我不确定这种方法的性能开销,当内存空间因数以千计的 mmap() 调用而极度碎片化时,内核/CPU 的性能如何?
  2. 如果在内核空间中访问未分配的内存,这种方法是否正确?例如read() 什么时候被调用?

对于绿色线程的堆栈分配还有其他(更好的)选项吗?在其他实现中如何分配绿色线程堆栈,例如围棋/Java?

最佳答案

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

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

为了兼容性,您可能应该使用 MAP_STACK也。这样你就不用自己写 SIGSEGV 处理程序了,堆栈会自动增长。可以按照此处所述设置边界 What does "ulimit -s unlimited" do?

如果你想要一个有界的堆栈大小,这通常是人们想要调用 sigaltstack(2) 时为信号处理程序所做的事情。 ,只需发出一个普通的 mmap 调用。

Linux 内核总是映射支持虚拟页面的物理页面,在第一次访问页面时捕获页面错误(可能不是在实时内核中,但肯定在所有其他配置中)。您可以使用 /proc/<pid>/pagemap接口(interface)(或者我写的这个工具 https://github.com/dwks/pagemap )来验证一下,如果你有兴趣的话。

关于c++ - C++ 绿色线程的堆栈分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35123250/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com