我有两个主题。线程1定期挂起线程2以收集一些统计信息。线程1需要为这些统计信息分配内存,而另一个线程被挂起。由于挂起的线程可以保持堆锁,因此如果线程1从同一堆分配内存,则可能发生死锁。
可能的解决方案:为线程1使用专用堆以避免死锁。
如果必须增加私有堆的大小会发生什么?必须再次使用某种全局锁来同步内存页面到堆的分配。因此,根据我的理解,如果线程2在暂停期间保持此全局锁定,则仍可能导致死锁。这是正确的还是使用一些特殊的“无锁原子”机制完成全局内存管理?
编辑:
线程2可以由CLR垃圾收集器暂停,也可以由我自己调用SuspendThread。通过调用HeapCreate创建私有堆。
答案 0 :(得分:2)
正如Hans Passant和David Heffernan已经指出的那样,SuspendThread
对于众所周知的问题很麻烦,如果有人可以提供帮助,那么永远不会暂停一个帖子,但是它阻止同步原语。这样,你可以提前知道它何时可以阻止,而且这不会在内存分配的中间。
显然,你的申请不太可能。
指定每个堆都受到来自多线程访问的单个锁的保护。因此,使用你想象的私有堆听起来像一个可行的解决方案。 HeapCreate
为指定的最大大小保留地址空间,并为初始大小提交内存。它之后并没有真正“增长”,而是只在已经保留的地址空间中提交更多内存
虽然没有指定堆必须如何操作(所以我们只能猜测),但这不应该是能够死锁的东西,因为它可能仅仅是对VirtualAlloc
的调用(或者取决于它是如何实现的,它可能只是一个防护页面上的页面错误,例如堆栈以这种方式提交其内存。)
VirtualAlloc
或虚拟内存/内存映射子系统不能拥有“更大的锁定”(好吧,他们肯定会,但不是用户进程拥有的那个!)因为如果他们是的,你可以在计算机上轻易地运行拒绝服务攻击,使计算机上的每个其他进程死锁。页面错误始终发生,因此一旦计算机上的任何进程挂起一个线程,就不会有任何进程(即使那些没有调用VirtualAlloc
的进程)也是安全的。
幸运的是,事实并非如此(这将是一场噩梦!)。
就您而言,使用私有堆的解决方案可能是一个很好的解决方案。
作为替代解决方案,既然您正在编写分析器并需要为“统计”(CPU使用,上下文切换,工作集大小,那种东西?)分配内存,可以假设这或多或少恒定的记忆量,或至少具有可预测上限的量 因此,您可以在暂停其他线程之前简单地分配内存。这意味着关于锁定的任何问题并不重要。
答案 1 :(得分:0)
您的假设条件如下:
当所有这些条件成立时,你就陷入僵局。