Isn't blindly using InvokeRequired just bad practice?
Asked Answered
P

2

21

I am a novice programmer so I could be completely mistaken here, but this issue bugs me more then it should.

This is actually a follow-up from this question.

The accepted answer was, that you have to call InvokeRequired in order to avoid some overhead, because there is a chance you are already operating on the UI thread.

In theory, I agree that it could save some time. After some tests I found out that using Invoke takes about twice the time compared to calling an operation normally (tests like setting the text of a label n times, or placing a very, very big string in a RichTextBox).

But! Then there is practice.

MSDN documentation says:

This property can be used to determine if you must call an invoke method, which can be useful if you do not know what thread owns a control.

In most cases, you do know when you try to access a control from another thread. Actually the only situation I can think of is, when the control is accessed from a method that can be called by thread X aswell as the owner thread. And that to me is a very unlikely situation.

And even if you genuinely don't know which thread tries to manipulate the control, there is the fact that the UI thread doesn't have to be updated that frequently. Anything between 25-30 fps should be okay for your GUI. And most of the changes made in the UI-controls takes far less then milliseconds to perform.

So if I understand corrrectly, the only scenario where you have to check if an invoke is required is when you don't know which thread is accessing the control and when the GUI update takes more than about 40 ms to finish.

Then there is the answer to this question I asked on http://programmers.stackexchange.com. Which states that you shouldn't be busy with premature optimisation when you don't need it. Especially if it sacrifices code readability.

So this brings me to my question: shouldn't you just use invoke when you know a different thread accesses a control, and only when you know your UI thread can access that piece of code and you find that it should run faster, that you should check if an Invoke is required?

PS: after proofreading my question it really sounds like I am ranting. But actually I am just curious why InvokeRequired is seemingly overused by many more-experienced-than-me programmers.

Primo answered 2/7, 2013 at 9:14 Comment(10)
Well done on your post.Diehl
I generally agree - if you expect a call to be coming in on a non-UI thread, there's little point in cluttering the code with InvokeRequired.Casey
@DanielHilgarth (I think) he doesn't, if you know the thread, you don't need to check the thread, if you don't know the thread, you should check.Croak
@T.Kiley: Yeah, I misunderstood it. That's why I already deleted my comment.Rightwards
@C.Lang, thanks, it took some time to write up :)Primo
My 2 cents: InvokeRequired is used so often because these programmers made the hurtful experience that it was needed, even though they were certain they wouldn't need it in the beginning. They learned to avoid having to think about whether it is needed in a given case or not, they just put it in always. Which makes them more productive (less time spent on trying to figure out if the might need it, less time spent on fixing the code later when it turns out they were wrong). This is good. It also makes them think less about what they are doing. This is bad.Gaselier
As you can see it's appreciated. Too many posts are sub-par. It's nice to see extra effort.Diehl
As a developer who does a lot of maintenance of others' poorly documented code, I hate superfluous checking. IME, the number of apps I've developed where an explicit UI method is called from both a secondary thread and the main UI thread is about zero.Logical
@MartinJames, exactly my point, thank you.Primo
stackoverflow.com/a/10209287 is a valid point. A control's handle should be created for Invoke to work. To be safe just check for InvokeRequired always.Wargo
R
9

You are taking things out of context here. The first question you linked linked another question which specifically was about writing a thread-safe method to access a UI control.

If you don't need a thread-safe access to a UI control, because you know you won't update it from another thread, then certainly, you shouldn't employ this technique. Simply update your UI control without using InvokeRequired or Invoke.

On the other hand, if the call will always originate in a thread other than the UI thread, simply use Invoke without first checking for InvokeRequired.

This leads to three simple rules:

  1. If you update the control only from the UI thread, use neither InvokeRequired nor Invoke
  2. If you update the control only from a thread other than the UI thread, use only Invoke.
  3. If you update the control from both the UI thread and other threads, use Invoke in combination with InvokeRequired.
Rightwards answered 2/7, 2013 at 9:21 Comment(2)
I agree, but shouldn't it be: "3. If you update the control from both the UI thread and other threads, and everything works as expected use Invoke. 4.If you update the control from both the UI thread and other threads and only using invoke is to slow, use Invoke in combination with InvokeRequired."?Primo
@Jordy: I wouldn't do that. Not because of premature optimization but because the combination of InvokeRequired and Invoke is a fixed pattern in a scenario where the calling thread can be anything.Rightwards
I
8

In practice people tend to call the same method from both the foreign and the owning thread. The usual pattern is that the method itself determines whether the thread is the owning thread. If it is, it executes the follow-up code. If it isn't the method calls its own self using Invoke this time.

One benefit of this is that it makes the code more compact, as you have one method related to the operation instead of two.

Another and probably more important benefit is that it reduces the chance that the cross thread exception will be raised. If both methods were available at any time and both threads could choose any of the two, then there would be a chance of a seemingly legitimate method call raising an exception. On the other hand, if there's only one method that adapts to the situation, it provides a safer interface.

Impost answered 2/7, 2013 at 9:19 Comment(6)
But in most code examples I see, it is used as SetTextBox(string text). But doesn't having to make methods like these already state the obvious, that you are trying to access it from outside the UI-thread? Seems to me when you want to change a TextBox from the ui thread, you'd probably just call TextBox.TextPrimo
@Jordy The point of this is that it allows you to not care about whether you're on the UI thread when calling the method (even if, at a given call spot, you would be sure). It completely leaves the check to the method itself. Having to make methods like this only means that you are in a potential cross-thread scenario, not that at any given time you are necessarily calling from the wrong thread.Impost
I think I start to see you're point but if you want to make your code thread-safe, shouldn't something like locking seem like a better sollution?Primo
@Jordy If you are talking about how the WPF controls themselves could have been implemented, then yes, possibly a lock would then be more convenient for the programmer that uses them. If you are talking about making your own code thread-safe given that the controls are the way they are, I don't see how a lock would help, because you're not dealing with a "helpless" resource, but with one that already has some kind of safety in place (and it's a kind of safety you don't have control over, so that you could theoretically make it cooperate with your lock).Impost
I assumed the exception you talked about in your answer was an exception caused by code being thread-unsafe. And I just posted the fist sollution against thread-unsafeness that came to mind. I see what you mean now.Primo
@Jordy Sort of. The cross thread exception is thrown because the WPF controls have some kind of write protection in place. (Whether this write protection could be said to constitute "thread safety" in the official meaning of the phrase, I'm not sure - perhaps someone else could explain that better.) But since that kind of protection is there, code that calls it must check its running thread before calling it, otherwise the calling code is thread-unsafe. And I think the only space the WPF controls leave you to make your calling code safe is the Dispatcher.Impost

© 2022 - 2024 — McMap. All rights reserved.