从私有堆分配内存会导致死锁吗?

时间:2014-01-16 08:46:47

标签: windows memory-management

我有两个主题。线程1定期挂起线程2以收集一些统计信息。线程1需要为这些统计信息分配内存,而另一个线程被挂起。由于挂起的线程可以保持堆锁,因此如果线程1从同一堆分配内存,则可能发生死锁。

可能的解决方案:为线程1使用专用堆以避免死锁。

如果必须增加私有堆的大小会发生什么?必须再次使用某种全局锁来同步内存页面到堆的分配。因此,根据我的理解,如果线程2在暂停期间保持此全局锁定,则仍可能导致死锁。这是正确的还是使用一些特殊的“无锁原子”机制完成全局内存管理?

编辑:

线程2可以由CLR垃圾收集器暂停,也可以由我自己调用SuspendThread。通过调用HeapCreate创建私有堆。

2 个答案:

答案 0 :(得分:2)

正如Hans Passant和David Heffernan已经指出的那样,SuspendThread对于众所周知的问题很麻烦,如果有人可以提供帮助,那么永远不会暂停一个帖子,但是它阻止同步原语。这样,你可以提前知道它何时可以阻止,而且这不会在内存分配的中间。

显然,你的申请不太可能。

指定每个堆都受到来自多线程访问的单个锁的保护。因此,使用你想象的私有堆听起来像一个可行的解决方案。 HeapCreate为指定的最大大小保留地址空间,并为初始大小提交内存。它之后并没有真正“增长”,而是只在已经保留的地址空间中提交更多内存 虽然没有指定堆必须如何操作(所以我们只能猜测),但这不应该是能够死锁的东西,因为它可能仅仅是对VirtualAlloc的调用(或者取决于它是如何实现的,它可能只是一个防护页面上的页面错误,例如堆栈以这种方式提交其内存。)

VirtualAlloc或虚拟内存/内存映射子系统不能拥有“更大的锁定”(好吧,他们肯定会,但不是用户进程拥有的那个!)因为如果他们是的,你可以在计算机上轻易地运行拒绝服务攻击,使计算机上的每个其他进程死锁。页面错误始终发生,因此一旦计算机上的任何进程挂起一个线程,就不会有任何进程(即使那些没有调用VirtualAlloc的进程)也是安全的。 幸运的是,事实并非如此(这将是一场噩梦!)。

就您而言,使用私有堆的解决方案可能是一个很好的解决方案。

作为替代解决方案,既然您正在编写分析器并需要为“统计”(CPU使用,上下文切换,工作集大小,那种东西?)分配内存,可以假设这或多或少恒定的记忆量,或至少具有可预测上限的量 因此,您可以在暂停其他线程之前简单地分配内存。这意味着关于锁定的任何问题并不重要。

答案 1 :(得分:0)

您的假设条件如下:

  • 线程2持有锁。
  • 线程2被暂停。
  • 线程1尝试获取锁定。
  • 线程2仅由线程1恢复。

当所有这些条件成立时,你就陷入僵局。