在pthreads线程的堆栈中预先故障的最佳方法是什么?

时间:2011-04-19 19:34:37

标签: linux memory-management stack pthreads real-time

我正在为嵌入式Linux系统中运行的实时程序编写代码。因为关键是我们不会在页面错误上无法预测,我想在堆栈中预先保留,以便我们使用的区域保证被mlockall()调用覆盖。

对于主线程来说这很简单;只需做几个大的alloca(),并确保每隔几页写一次。这是有效的,因为在程序启动时,堆栈限制远远大于我们需要的数量;我们最终确定了我们预先确定了多少。

但是,对于pthread堆栈,它们是否也将使用MAP_GROWSDOWN进行分配?如果是这样的话,考虑到:

,最好的方法是将它们预先存在
  1. 我们不知道libc startup
  2. 消耗了多少(已知的)堆栈大小
  3. 我们不希望为堆栈分配比必要更多的内存
  4. 我知道我可以使用pthread_attr_setstack传递一个手动分配的堆栈,但这会使线程后的清理变得复杂,所以如果可能的话我宁愿避免这种情况。

    因此,执行此预测的最佳方法是什么?如果有一种简单的方法来找出堆栈的下限(就在保护页面上方)就足够了;在这一点上,我可以简单地从那里写入每个页面到当前的堆栈指针。

    请注意,便携性不是问题;我们很高兴有一个仅适用于x86-32和Linux的解决方案。

2 个答案:

答案 0 :(得分:3)

如果您使用pthread_attr_setstacksize,您仍然可以使用已知大小进行自动分配。

glibc nptl在堆栈之间留下了保护页面,所以你也可以设置一个SEGV处理程序,然后简单地涂鸦直到你出错,然后longjmp退出循环。那太丑了!

编辑:真正不可移植的方式是打开/proc/self/maps来找到你的筹码!

答案 1 :(得分:1)

是肯定的。如果在pthread_create之前调用了mlockall(MCL_CURRENT | MCL_FUTURE),则在启动线程时会发生线程堆栈的页面错误。之后,在线程中访问堆栈时不会再出现页面错误。 所以人们总是为新创建的线程设置合适的线程大小,以避免为将来的线程锁定太多内存。 看一眼: https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example

如果将线程堆栈大小更改为7MB,您将看到: 初始计数:Pagefaults,Major:0(允许> = 0),Minor:190(允许> = 0) mlockall()生成:Pagefaults,Major:0(允许> = 0),Minor:393(允许> = 0) malloc()和触摸生成:Pagefaults,Major:0(允许> = 0),次要:25633(允许> = 0) 第二个malloc()和使用生成:Pagefaults,Major:0(允许0),Minor:0(允许0)

查看ps -leyf的输出,看看RSS现在大约是100 [MB] 按退出 我是一个带有堆栈的RT线程,在使用过程中不会生成页面错误,stacksize = 7340032 由创建线程引起:Pagefaults,Major:0(Allowed> = 0),Minor:1797(Allowed> = 0) 使用线程堆栈引起:Pagefaults,Major:0(允许0),Minor:0(允许0)

创建线程时发生1797页错误,大约是7MB。 -barry