UI and worker thread

E

emma middlebrook

Hi

My main UI thread needs to create a worker thread. To signal that the
work is finished the UI should be updated.

I'm worried about that worker thread calling back via a delegate when
it has finished its work. UI stuff is message-queue based and handled
by a single thread spinning the standard message loop. But the worker
thread calling back is obviously a different thread and, of course,
isn't going to be 'serialized' by the message queue in any way.

So, how best to do update the UI safely?

Hope this makes sense.

Emma Middlebrook
 
J

Jon Skeet [C# MVP]

emma middlebrook said:
My main UI thread needs to create a worker thread. To signal that the
work is finished the UI should be updated.

I'm worried about that worker thread calling back via a delegate when
it has finished its work. UI stuff is message-queue based and handled
by a single thread spinning the standard message loop. But the worker
thread calling back is obviously a different thread and, of course,
isn't going to be 'serialized' by the message queue in any way.

So, how best to do update the UI safely?

Use Control.Invoke - that makes sure the specified delegate is called
in the UI thread.
 
T

TT \(Tom Tempelaere\)

Jon Skeet said:
Use Control.Invoke - that makes sure the specified delegate is called
in the UI thread.

Hi,

Invoke will indeed 'serialize' it. A call to Invoke will block until the
delegate is executed on the UI thread.

BeginInvoke on the other hand will post the task of invoking the delegate in
the thread's queue and then return. The delegate will be invoked as soon as
the UI thread sees fit (queue based). This prevents the worker thread from
blocking, and allows asynchronous execution. A call to EndInvoke will block
until the delegate was invoked and returns results if the delegate returns
results. The call to Endvoke isn't necessary if the delegate doesn't return
results.

These are all methods of the ISynchronizeInvoke interface. The Control class
implements this interface.

http://msdn.microsoft.com/library/d...omponentmodelisynchronizeinvokeclasstopic.asp

Cheers,
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_N_0SPA|/
\|[email protected]|/\|APS0_N_> said:
BeginInvoke on the other hand will post the task of invoking the delegate in
the thread's queue and then return. The delegate will be invoked as soon as
the UI thread sees fit (queue based). This prevents the worker thread from
blocking, and allows asynchronous execution. A call to EndInvoke will block
until the delegate was invoked and returns results if the delegate returns
results. The call to Endvoke isn't necessary if the delegate doesn't return
results.

Note that although the call to EndInvoke isn't necessary (at all, as
far as I'm aware, whether or not there's a return value) for
Control.BeginInvoke, you should *always* use it for other asynchronous
invocations - even if failing to call EndInvoke doesn't cause a leak
now, it's not guaranteed that it won't in the future. The UI guys have
apparently given assurances that Control.BeginInvoke can always be
"fire and forget" though.

It's not terribly difficult to write a wrapper which will make sure
EndInvoke is called for you if you want to avoid having to call it
yourself. There's a good sample that was posted on one of the mailing
lists - I'll find it if you're interested.
 
T

TT \(Tom Tempelaere\)

Jon Skeet said:
TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_N_0SPA|/


Note that although the call to EndInvoke isn't necessary (at all, as
far as I'm aware, whether or not there's a return value) for
Control.BeginInvoke, you should *always* use it for other asynchronous
invocations - even if failing to call EndInvoke doesn't cause a leak
now, it's not guaranteed that it won't in the future. The UI guys have
apparently given assurances that Control.BeginInvoke can always be
"fire and forget" though.

The ISynchronizeInvoke.BeginInvoke and Control help don't mention, but you
can get around this by not having the delegate return results I guess. They
should have documented better.
It's not terribly difficult to write a wrapper which will make sure
EndInvoke is called for you if you want to avoid having to call it
yourself. There's a good sample that was posted on one of the mailing
lists - I'll find it if you're interested.

I don't see any direct use for me. Thanks.

Cheers,
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_N_0SPA|/
\|[email protected]|/\|APS0_N_> said:
The ISynchronizeInvoke.BeginInvoke and Control help don't mention, but you
can get around this by not having the delegate return results I guess. They
should have documented better.

No, I believe even if the delegate doesn't return any results, you
still need to call EndInvoke in the general case in order to
*guarantee* that there won't be any leaks. Control.BeginInvoke is a
special case here, where you don't need to.

And yes, none of this is explicitly documented :(
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_N_
No, I believe even if the delegate doesn't return any results, you
still need to call EndInvoke in the general case in order to
*guarantee* that there won't be any leaks. Control.BeginInvoke is a
special case here, where you don't need to.

So what you are telling is that the implementation of the
ISynchronizeInvoke interface for the Control class shows this
behaviour (not having to call EndInvoke for each BeginInvoke)? And
that this behaviour just isn't guaranteed for other implementers of
the ISynchronizeInvoke interface?
Exactly.

Anyway, it can be a real burden to have to call EndInvoke even for
delegates that don't return results. I personally don't call
EndInvoke when calling BeginInvoke on a Control, and I wouldn't use
BeginInvoke for a delegate that returns results (why would I?).

Well, you don't necessarily need the return value of the delegate, and
you can get the return value from EndInvoke if you need it anyway. I
would choose whether or not to call BeginInvoke based on my threading
requirements, not on the delegate's return type.
Unless you can have EndInvoke called behind the screens of course,
implicitly. Then the "Auto-EndInvoke" class you mentioned earlier
would come in handy.

Right.

http://msdn.microsoft.com/msdnmag/issues/04/01/BasicInstincts/
and
http://staff.develop.com/woodring/dotnet/#FireAndForget

may be of interest to you.
Maybe you could add it to your examples on your
website, I will be happy to check it out. I'm curious: does it use
another thread to finish things?

Not sure - I'll have to look more carefully when I have some time.
And yes, none of this is explicitly documented :(

Indeed, that is somewhat strange. Me :( too.

Interestingly, one of the webpages claims it *is* now documented, but I
can't see it in the docs for BeginInvoke or EndInvoke...
 
T

TT \(Tom Tempelaere\)

Jon Skeet said:
TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_N_
0SP@|/\|[email protected]|/\|@PS0_N_>> wrote: [...]
Maybe you could add it to your examples on your
website, I will be happy to check it out. I'm curious: does it use
another thread to finish things?

Not sure - I'll have to look more carefully when I have some time. [...]

The workaround uses a thread from the threadpool to invoke the delegate,
using Delegate.DynamicInvoke. But I see no synchronization with the UI
thread.
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) said:
The workaround uses a thread from the threadpool to invoke the
delegate, using Delegate.DynamicInvoke. But I see no synchronization
with the UI thread.

There doesn't need to be any synchronization with the UI thread -
Control.BeginInvoke doesn't require a workaround, because the UI team
have guaranteed that that particular method call won't leak.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top