以下代碼是一個簡化的概念驗證。 在Windows窗體應用程序中有一個FormClosing事件處理程序來執行一些清理。應用程序啓動一些使用Control.Invoke在窗體上寫入的線程。我知道我可以使用Control.BeginInvoke,但我想更好地瞭解發生了什麼並找到另一個解決方案。Control.Invoke出現意外的塊狀況
List<Thread> activeThreadlist;
volatile bool goOnPolling = true;
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
goOnPolling = false;
Thread.Sleep(1000);
foreach (Thread element in activeThreadlist)
if (element.IsAlive)
element.Abort();
}
一個標誌被設置爲false,以停止對線程的循環,他們有時間終止,如果一個人還活着,它終止了與中止。
這裏是由其他線程執行的代碼:
while (goOnPolling)
{
//some long elaboration here
if (!goOnPolling) continue;
aControl.Invoke(new Action(() =>
{
//display some result about the elaboration
}));
if (!goOnPolling) continue;
//some long elaboration here
}
在的情況下爲約50%時關閉窗體上Control.Invoke線程塊,這樣它們不會在睡眠時間終止和Abort被調用。我認爲在調用Invoke之前檢查標誌goOnPolling在99.999%的情況下足夠了,但我錯了。正如代碼所述,線程做了很長的闡述(至少100ms),所以我預計goolnolling可能會在他們期間改變。爲什麼我錯了?是否有另一種簡單的解決方案,而不需要重複創建額外的線程的BeginInvoke?
更新
閱讀評論後,我意識到標題是錯誤的。我最初寫死鎖但它只是一個意想不到的(對我來說)塊條件。一開始我無法理解爲什麼我的線程在等待終端1000ms後仍然存在,所以我把一個中止找出來。我完全誤解了Invoke和BeginInvoke之間的區別,謝謝澄清。
@喬恩乙
我同意突破更適合比繼續但代碼裏面,而(goOnPolling)塊,所以我只能節省一些CPU週期,僅此而已。
任何想法爲什麼經常goOnPolling在Invoke的早期階段發生變化?如果我進行長時間的闡述,它應該在大多數時候發生。
'BeginInvoke'不應該創建額外的線程,它只是在*現有* UI線程上排隊工作。創建一個新的線程完全與'BeginInvoke'設計的目的相反。 –
你確定你最後一句話嗎?據我所知,在UI線程上執行'Invoke'和'BeginInvoke',在返回之前只有'Invoke'塊。即'Invoke' ='BeginInvoke' +等待執行。你可能會混淆'委託''Invoke' /'BeginInvoke',請參閱https://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvoke。使用'Control.Invoke'的唯一原因是在繼續調用線程之前需要調用的動作完成。 – Rotem
我100%肯定。 'Invoke'在消息循環中排隊執行,然後等待它完成。 'BeginInvoke'完成了完全相同的事情,但在完成之前不會阻塞。這可能是你的僵局來自哪裏。您的UI線程正在等待子線程,並且子線程正在UI上等待完成。 –