winforms async calls for the beginner

C

Chandy

Hi,

I am trying to get my head around threading and delegates and have
been reading the "Calling Synchronous Methods Asynchronously" document
on MSDN but, strangely, can't get any of the examples to fit in my
head with what I want. I say strangely because I thought what I want
would be very basic! Can anyone advise as to how to approach the
following problem?:

WinFormA has a timer which needs to call a static method in another
class on a schedule, but of course not be blocked by the call. Also,
it needs to not call the method again if the timer ticks and the
previous call has not yet completed.

Checking a simple boolean value on the form before calling the method,
which is updated on the EndInvoke of the delegate, would seem to do
it, but I just can't seem to find an example that doesn't block the
form gui thread until the result comes back. Note also that I don't
care about any result, I just want to call the method async only once
at a time.

Thanks,

Chandy
 
P

Peter Duniho

Chandy said:
[...]
WinFormA has a timer which needs to call a static method in another
class on a schedule, but of course not be blocked by the call. Also,
it needs to not call the method again if the timer ticks and the
previous call has not yet completed.

Checking a simple boolean value on the form before calling the method,
which is updated on the EndInvoke of the delegate, would seem to do
it, but I just can't seem to find an example that doesn't block the
form gui thread until the result comes back. Note also that I don't
care about any result, I just want to call the method async only once
at a time.

If you are calling Delegate.BeginInvoke(), then you are passing an
AsyncCallback delegate parameter to that method (or at least, you should
be). In the method referenced by that delegate, you call EndInvoke() as
well as return your boolean value to its initial state.

Do make sure the boolean is "volatile" so that the multiple threads
accessing it always have the current value.

If you call EndInvoke() from the same thread in which you called
BeginInvoke(), before the delegate has been completed asynchronously,
then yes...that thread will block until the original delegate is done.
The solution is simply "don't do that". Let the callback call
EndInvoke() instead (as I describe above).

You aren't specific about the examples you have found, or about the code
you've tried, so it's difficult to provide anything any more specific
than that. If the above information doesn't address your problem, then
if you can post a concise-but-complete example of code that shows what
you've got so far, it should be possible to provide more complete advice.

Pete
 
C

Chandy

Chandy said:
[...]
WinFormA has a timer which needs to call a static method in another
class on a schedule, but of course not be blocked by the call. Also,
it needs to not call the method again if the timer ticks and the
previous call has not yet completed.
Checking a simple boolean value on the form before calling the method,
which is updated on the EndInvoke of the delegate, would seem to do
it, but I just can't seem to find an example that doesn't block the
form gui thread until the result comes back. Note also that I don't
care about any result, I just want to call the method async only once
at a time.

If you are calling Delegate.BeginInvoke(), then you are passing an
AsyncCallback delegate parameter to that method (or at least, you should
be). In the method referenced by that delegate, you call EndInvoke() as
well as return your boolean value to its initial state.

Do make sure the boolean is "volatile" so that the multiple threads
accessing it always have the current value.

If you call EndInvoke() from the same thread in which you called
BeginInvoke(), before the delegate has been completed asynchronously,
then yes...that thread will block until the original delegate is done.
The solution is simply "don't do that". Let the callback call
EndInvoke() instead (as I describe above).

You aren't specific about the examples you have found, or about the code
you've tried, so it's difficult to provide anything any more specific
than that. If the above information doesn't address your problem, then
if you can post a concise-but-complete example of code that shows what
you've got so far, it should be possible to provide more complete advice.

Pete

Hi Pete,

I've read and tried so much it's hard to be specific but I think that
I have now settled on using the mechanism described in example 8 on
this page: http://www.ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html?page=2
It seems to be the best explanation of all this that I have come
across so far.

You mention using 'volatile'. I haven't been at C# that long and
didn't know that existed :) If I had, it would have got around the
issue mentioned in the article above that the callback does not go
back to the main thread, which was the problem I saw with it. Now,
though, I see that volatiles are not all that great an idea
themselves? What do you make of the article at
http://blogs.labtech.epitech.net/blogs/jaylee/archive/2004/08/05/704.aspx
regarding volatiles?

Thanks,

Chandy
 
P

Peter Duniho

Chandy said:
I've read and tried so much it's hard to be specific but I think that
I have now settled on using the mechanism described in example 8 on
this page: http://www.ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html?page=2
It seems to be the best explanation of all this that I have come
across so far.

I've assumed as much, based on your original post. That is, not the
specific article you mention, but the general technique of calling
Delegate.BeginInvoke(). Thus, my original reply should be applicable to
your situation.
You mention using 'volatile'. I haven't been at C# that long and
didn't know that existed :) If I had, it would have got around the
issue mentioned in the article above that the callback does not go
back to the main thread, which was the problem I saw with it.

Well, the article you mention does bring up Control.Invoke() and
Control.BeginInvoke() (which is completely different from
Delegate.BeginInvoke()), which is an alternate way of addressing that issue.

But given that you just want to set a single 32-bit value, contained in
your derived class (and so doesn't need to go through any of the regular
Forms control stuff), IMHO using "volatile" should be fine.
Now,
though, I see that volatiles are not all that great an idea
themselves? What do you make of the article at
http://blogs.labtech.epitech.net/blogs/jaylee/archive/2004/08/05/704.aspx
regarding volatiles?

I disagree with your impression of the article. The author is not
saying that "volatiles are not all that great an idea", he's saying that
you need to understand what using "volatile" actually does.

In particular, the scenario he's talking about involves fetching a
value, modifying it, and then storing it back to the variable. That is
indeed a situation not completely addressed by using the "volatile"
keyword, and does require some form of synchronization, such as the use
of the "lock()" statement the article demonstrates.

But in your situation, you have a well-defined pattern of setting and
fetching that doesn't need the same kind of synchronization shown in
that article. In particular, only one thread will ever set the boolean
to "true", and it will do so only when the other thread has set it to
"false" and exited. There's no chance of the first thread setting the
variable to "true" and then having it incorrectly set immediately to
"false" again by some other thread, because the order of the setting is
very much well-defined and doesn't allow for that conflict.

Likewise the converse. The second thread can safely set the variable to
"false" without worrying about some other thread overwriting that value
with "true" again, because the only thread that will ever set the value
to "true" will only do so once it's observed the value as being "false".

So, the only thing you really need to worry about here is that one
thread, running on a given CPU, will set a value not observable by
another thread, running on a different CPU, because the CPUs are using a
non-shared copy of the variable. Using the "volatile" keyword ensures
that the two threads are always using the same data. Which is what you
want to happen.

Pete
 
B

Ben Voigt [C++ MVP]

Chandy said:
Hi,

I am trying to get my head around threading and delegates and have
been reading the "Calling Synchronous Methods Asynchronously" document
on MSDN but, strangely, can't get any of the examples to fit in my
head with what I want. I say strangely because I thought what I want
would be very basic! Can anyone advise as to how to approach the
following problem?:

WinFormA has a timer which needs to call a static method in another
class on a schedule, but of course not be blocked by the call. Also,
it needs to not call the method again if the timer ticks and the
previous call has not yet completed.

Maybe you just want to look at the IsCompleted propertly of the IAsyncResult
returned from BeginInvoke?
 

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