2014-01-16 78 views
1

我有兩個線程。線程1定期掛起線程2以收集一些統計信息。線程1需要爲這些統計分配內存,而另一個線程被掛起。由於掛起的線程可能存放堆鎖,因此如果線程1從同一堆中分配內存,可能會發生死鎖。從私有堆分配內存會導致死鎖嗎?

可能的解決方案:爲線程1使用私有堆以避免死鎖。

如果必須增加私有堆的大小會發生什麼?必須再次出現某種全局鎖定,將內存頁面的分配與堆分配同步。因此,根據我的理解,如果線程2在暫停期間持有此全局鎖定,則仍有可能導致死鎖。這是正確的還是用一些特殊的「無鎖原子」機制完成全局內存管理?

編輯:

線程2可以由CLR垃圾收集器,或撥打我自己SuspendThread暫停。通過調用HeapCreate來創建私人堆。

+0

你怎麼暫停線程? –

+0

請參閱已編輯的問題。 – Tom

+0

這就是爲什麼SuspendThread()是邪惡的,並且在.NET Framework中有[Obsolete]屬性。不要使用它。 –

回答

2

正如指出的漢斯帕桑特和大衛·赫弗南已經,SuspendThread麻煩與著名的問題,如果一個能幫助它,一會從未掛起線程,但有它在原始同步塊。這樣,你就可以提前知道它何時可以及何時不能阻塞,並且這不會在內存分配的中間。

很明顯,這對您的應用程序來說不太可能。

指定每個堆由多線程訪問中的單個鎖保護。因此,使用您所設想的私人堆聽起來像是一個可行的解決方案。 HeapCreate爲指定的最大大小保留地址空間併爲初始大小提交內存。之後它並不真正「增長」,而只是在已經保留的地址空間中提交了更多的內存。
雖然沒有指定堆的確切操作(所以我們只能猜測),但這不是應該能夠死鎖的東西,因爲它可能僅僅是調用VirtualAlloc(或者取決於它如何實現,它可能會只在頁面上出現頁面錯誤,例如堆棧以這種方式提交它的內存)。

VirtualAlloc或虛擬內存/存儲映射子系統不能有「更大的鎖」(當然,他們肯定做,但不是一個真實的用戶進程擁有的!),因爲如果他們這麼做,你將能夠平凡在計算機上運行拒絕服務攻擊,在計算機上每隔一個進程出現死鎖。頁面錯誤一直在發生,所以沒有任何進程(即使是那些沒有調用VirtualAlloc)將是安全的,一旦任何進程在計算機上掛起一個線程。幸運的是,情況並非如此(這將是一場噩夢!)。

就目前而言,您使用私有堆的解決方案可能是一個很好的解決方案。作爲一種替代解決方案,由於您正在編寫一個分析器,並且需要爲「統計」(CPU使用,上下文切換,工作集大小,類似的東西?)分配內存,所以可以假定這是更多的少一個恆定的內存量,或者至少一個具有可預測的上限的量。
因此,您可能會簡單地在之前分配內存,以暫停其他線程。這意味着有關鎖的任何問題都無關緊要。

0

你的假設條件如下:

  • 線程2持有鎖。
  • 線程2暫停。
  • 線程1嘗試獲取鎖。
  • 線程2將只能由線程1

當所有這些條件成立恢復,你有死鎖。