For example, if I'm adding items to a List or incrementing a counter, can a call from one worker thread interrupt another? Each BeginInvoke is it's own call, but modifying the data seems like it could still be a problem.
No, an invoke call cannot be interrupted by another such call. In fact, it cannot be interrupted by any other operation on the UI thread. This is the reason that if you put your UI thread to work the UI itself "hangs" (input and paint messages get queued for processing, but they cannot interrupt the work you are doing).
However, adding items to a List<T>
(is that what you mean?) or incrementing a counter are not UI manipulations. Why are you doing them on the UI thread?
It's true that invoking such operations on the UI thread gives you thread-safe locking as a side effect, but it's not really free: it's much more expensive than doing a simple lock
on the worker thread.
You should consider switching to this approach, which will also solve your "too many updates = lag" problem:
- Data variables (lists, counters, whatever) are manipulated directly by worker threads. Use appropriate locking constructs (
lock
,Interlocked
methods, concurrent collections, whatever) to provide thread-safety. - Whenever a worker thread modifies a data variable, it also sets a global
modified
flag totrue
. - Nothing gets marshalled to the UI thread (invoked).
- Meanwhile, the UI thread sets up a timer to fire every e.g. half second. Whenever the timer fires, the UI thread checks the value of
modified
and resets it tofalse
(you can do this lock-free withInterlocked.CompareExchange
). - If the UI thread finds that data has been modified, it locks all data variables and repaints the UI as necessary.
This way you only get at most one (expensive!) UI update on every timer tick, and the UI will not lag no matter how much data is coming in from the worker threads. Plus, you can pick the timer interval to be as short or as long as you like.