Can allocating memory from a private heap cause a deadlock?

I have two threads. Thread 1 suspends thread 2 regularly to collect some statistics. Thread 1 needs to allocate memory for those statistics while the other thread is suspended. Since the suspended thread may hold the heap lock, a deadlock could occur if memory is allocated from the same heap by thread 1.

Possible solution: Use a private heap for thread 1 to avoid deadlocks.

What happens if the size of the private heap must be increased? There must be again some kind of global lock that synchronizes assignment of memory pages to heaps. So in my understanding it's still possible to cause a deadlock if thread 2 holds this global lock during suspension. Is this correct or is global memory management done with some special "lockfree atomic" mechanism?

Edit:

Thread 2 may be suspended by the CLR garbage collector or by calling SuspendThread on my own. A private heap is created by calling HeapCreate.


As pointed out by Hans Passant and David Heffernan already, SuspendThread is troublesome with well-known issues, and if one can help it, one would never suspend a thread, but have it block on a synchronization primitive. That way, you know ahead of time when it can and when it cannot block, and this won't be in the middle of a memory allocation.

Obviously that isn't quite possible for your application.

It is specified that each heap is protected by a single lock from multithreaded access. Using a private heap as you have envisioned therefore sounds like a workable solution. HeapCreate reserves address space for the specified maximum size and commits memory for the initial size. It does not truly "grow" thereafter, rather it only commits more memory in the already reserved address space.
While it is not specified how exactly a heap must operate (so we can only guess), this is not something that should be able to deadlock, as it is likely a mere call to VirtualAlloc (or depending how it's implemented, it might only be a pagefault on a guard page, for example the stack commits its memory that way).

VirtualAlloc or the virtual memory / memory mapping subsystem cannot have a "bigger lock" (well, they certainly do, but not one that's owned by user processes!) because if they did, you would be able to trivially run a denial of service attack on a computer, deadlocking every other process on the computer. Page faults happen all the time, so no process (even those that are not calling VirtualAlloc ) would be safe once any process on the computer suspended a thread. Luckily, that isn't the case (this would be a nightmare!).

Insofar, your solution of using a private heap is probably a good one.

As an alternative solution, since you are writing a profiler and need to allocate memory for "statistic" (CPU used, context switches, working set size, that kind of stuff?), one may assume that this is more or less a constant amount of memory, or at least an amount with a predictable upper bound.
Thus, you might simply allocate memory before suspensing the other thread. Which means any questions regarding the lock don't really matter.


Your assumed condition is as follows:

  • Thread 2 holds a lock.
  • Thread 2 is suspended.
  • Thread 1 attempts to acquire the lock.
  • Thread 2 will only be resumed by thread 1.
  • When all those conditions hold, you have deadlock.

    链接地址: http://www.djcxy.com/p/31610.html

    上一篇: 为什么释放堆内存比分配内存慢得多?

    下一篇: 从私有堆分配内存会导致死锁?