2013-04-12 66 views
1

由於我的應用程序有效,所以我沒有問題(但),但我想了解發生了什麼,所以我稍後不會遇到麻煩。 (我主要是一個數據庫/網絡應用程序員,所以線程通常不是我的東西!)調用UI線程的多個線程:表單數據需要鎖定?

簡版:用戶界面是否需要在多線程更新時鎖定表單數據?

我有掃描某些內容文件,並將結果顯示給用戶一個簡單的Winforms應用程序(使用DataGridViews)。我起初在UI線程中完成了這一切,但瞭解到這不是一個好主意,並且決定使用ThreadPool.QueueUserWorkItem來處理[ProcessorCount]項目集合。這可以正常工作,使用委託和BeginInvoke功能在發現UI時將結果發送到UI。 (儘管有時有太多的結果和UI仍然滯後,但這是另外一個問題。)

工作線程是完全隔離的,做自己的事。我理解多線程的概念,並且需要知道同時訪問共享數據。然而,我不完全清楚的是當各種線程調用UI線程來更新它時會發生什麼。只有UI會更新控件(和表單級別的變量),但由於調用來自其他線程,這是如何實現的?例如,如果我將項目添加到列表或遞增計數器,是否可以將來自一個工作線程的調用中斷另一箇中斷?每個BeginInvoke都是自己的調用,但修改數據似乎仍然可能是一個問題。的的BeginInvoke的例子

無我發現提及任何需要在用戶界面鎖定。這兩個主題相關的,但仍然不給我在尋找確切的答案:

Using Control.Invoke() in place of lock(Control)

What's the difference between Invoke() and BeginInvoke()

+1

爲什麼你應該從單一線程進行所有UI操作:UI線程。 –

回答

4

例如,如果我將項目添加到列表或遞增一個計數器, 可以調用一個工作線程中斷另一個?每個BeginInvoke 是它自己的調用,但修改數據似乎仍然可能是 的一個問題。

不,一個調用調用不能被另一個這樣的調用中斷。實際上,它不能被UI線程上的其他操作中斷任何。這就是爲什麼如果你讓你的UI線程工作,UI自己會「掛起」(輸入和繪製消息被排隊等待處理,但它們不能中斷你正在做的工作)。

然而,添加項目到List<T>(就是你的意思?),或者增加計數器不是UI操作。你爲什麼要在UI線程上做它們?

這是真的,在UI線程上調用這樣的操作讓你的線程安全鎖的副作用,但它不是真正的自由:它是比工作線程上做一個簡單的lock更加昂貴。

您應該考慮切換到這種做法,這也將解決你的「太多的更新滯後=」問題:

  • 數據變量(表,計數器,等等)是由工作線程直接操作。使用適當的鎖定結構(lock,Interlocked方法,concurrent collections,無論如何)來提供線程安全性。
  • 只要工作程序線程修改數據變量,它也會將全局modified標誌設置爲true
  • Nothing編組到UI線程(調用)。
  • 同時,UI線程設置一個定時器來觸發每個例如半秒鐘。每當定時器觸發時,UI線程將檢查modified的值並將其重置爲false(您可以使用Interlocked.CompareExchange鎖定此鎖定)。
  • 如果UI線程發現數據已被修改,它將鎖定所有數據變量並根據需要重新繪製UI。

這樣,每次計時器滴答只能得到最多一個(昂貴的!)UI更新,而且不管工作線程中有多少數據進入,UI都不會滯後。另外,您可以選擇計時器間隔時間短或只要你喜歡。

+0

謝謝,聽起來像這就是我應該做的。我想添加到列表/改變UI上的計數器只是因爲它很方便,我沒有太多的經驗。 :)我需要一些用於UI操作的數據(例如緩存結果),並且在我從其他線程獲取它們之後直接將其存儲在表單中似乎是有意義的。但是工作線程可以像其他地方一樣容易地將它們存儲在UI中,就像你所建議的那樣。 – Bitwise