![]() | |
![]() |
| | Thread Tools | Search this Thread | Display Modes |
#1
| |||
| |||
|
#2
| |||
| |||
|
|
i have encountered a strange behaviour when using ref parameters with delegates. basically the changed value is not reflected back to the original calling method. to prove the point, run this simple console application. it sets a string variable 's' with the current number of Ticks, then invokes a method via a delegate, waits for it to finish, and outputs the supposed-to-be-changed value. the value is changed in the method, but is not reflected back. [snip] // invoke a method using a delegate new TestByRefDelegate(this.TestByRef).BeginInvoke(ref s, null, null); Thread.Sleep(500); // wait until the other thread is finished Console.WriteLine("After delegate: \t" + s); can anyone shed some light on this? i just realised that it's of course because the value is changed on the new thread, but that is disposed of as soon as it finishes. this then begs the question, why does the compiler allow delegates with ref parameters, since it is impossible for the value to survive the lifetime of the thread? |
#3
| |||
| |||
|
|
"Tim_Mac" <mackey.tim (AT) gmail (DOT) com> wrote: i have encountered a strange behaviour when using ref parameters with delegates. basically the changed value is not reflected back to the original calling method. to prove the point, run this simple console application. it sets a string variable 's' with the current number of Ticks, then invokes a method via a delegate, waits for it to finish, and outputs the supposed-to-be-changed value. the value is changed in the method, but is not reflected back. [snip] // invoke a method using a delegate new TestByRefDelegate(this.TestByRef).BeginInvoke(ref s, null, null); Thread.Sleep(500); // wait until the other thread is finished Console.WriteLine("After delegate: \t" + s); can anyone shed some light on this? i just realised that it's of course because the value is changed on the new thread, but that is disposed of as soon as it finishes. this then begs the question, why does the compiler allow delegates with ref parameters, since it is impossible for the value to survive the lifetime of the thread? Calling EndInvoke is not optional. It's never optional: you must always call EndInvoke. It may acquire resources (such as synchronization objects) which need to be released on the call to EndInvoke. The value doesn't get returned until you call EndInvoke, because otherwise the background thread would have a reference to a variable allocated on the stack, and that's not allowed because the method might return without ever calling EndInvoke(), which would allow the threadpool thread executing the delegate to write to whatever random stack frame that has replaced the calling frame. Check this out (C# 2.0): ---8<--- using System; using System.Threading; class App { delegate void TwiddleString(ref string value); static void Main() { // With End* call. TwiddleString twiddle = delegate(ref string value) { Thread.Sleep(500); value = "bar!"; }; string foo = "foo!"; IAsyncResult res = twiddle.BeginInvoke(ref foo, null, null); Thread.Sleep(700); Console.WriteLine(foo); twiddle.EndInvoke(ref foo, res); Console.WriteLine(foo); } } --->8--- -- Barry -- http://barrkel.blogspot.com/ |
#4
| |||
| |||
|
|
many thanks for your enlightening post. i've been using Delegates for a good long time never using EndInvoke, typically raising an event from the delegate to signify the task completion. but this obviously isn't the whole story! |
#5
| |||
| |||
|
|
can anyone shed some light on this? i just realised that it's of course because the value is changed on the new thread, but that is disposed of as soon as it finishes. this then begs the question, why does the compiler allow delegates with ref parameters, since it is impossible for the value to survive the lifetime of the thread? Calling EndInvoke is not optional. It's never optional: you must always call EndInvoke. It may acquire resources (such as synchronization objects) which need to be released on the call to EndInvoke. |
#6
| |||
| |||
|
|
Barry Kelly <barry.j.kelly (AT) gmail (DOT) com> wrote: can anyone shed some light on this? i just realised that it's of course because the value is changed on the new thread, but that is disposed of as soon as it finishes. this then begs the question, why does the compiler allow delegates with ref parameters, since it is impossible for the value to survive the lifetime of the thread? Calling EndInvoke is not optional. It's never optional: you must always call EndInvoke. It may acquire resources (such as synchronization objects) which need to be released on the call to EndInvoke. Small exception to that - for Control.BeginInvoke, you don't need to call EndInvoke. See http://blogs.msdn.com/cbrumme/archiv.../06/51385.aspx |
#7
| |||
| |||
|
|
Small exception to that - for Control.BeginInvoke, you don't need to call EndInvoke. See http://blogs.msdn.com/cbrumme/archiv.../06/51385.aspx It's in the comment section: CB> Last night I sent an email to the WinForms folks asking this same CB> question. Like you, I suspect the EndInvoke is optional on Control. CB> (I looked through the code, but that's no substitute for a statement CB> from the authors). As you say, this API doesn't quite match the CB> managed async programming model anyway. I'll reply back as soon as I CB> get official word. |

#8
| |||
| |||
|
|
I know it's on a blog rather than being part of the documentation, but I think it's still reasonably definitive. Let's say I trust Chris Brumme when it comes to this kind of thing ![]() |
#9
| |||
| |||
|
|
You missed the bit later on - Chris Brumme again: quote Chris Brumme said: I just got the official word from the WinForms team. It is not necessary to call Control.EndInvoke. You can call BeginInvoke in a "fire and forget" manner with impunity. May 12, 2003 5:30 PM /quote |
|
I know it's on a blog rather than being part of the documentation, but I think it's still reasonably definitive. Let's say I trust Chris Brumme when it comes to this kind of thing ![]() |
#10
| |||
| |||
|
|
Barry Kelly <barry.j.kelly (AT) gmail (DOT) com> wrote: Small exception to that - for Control.BeginInvoke, you don't need to call EndInvoke. See http://blogs.msdn.com/cbrumme/archiv.../06/51385.aspx It's in the comment section: CB> Last night I sent an email to the WinForms folks asking this same CB> question. Like you, I suspect the EndInvoke is optional on Control. CB> (I looked through the code, but that's no substitute for a statement CB> from the authors). As you say, this API doesn't quite match the CB> managed async programming model anyway. I'll reply back as soon as I CB> get official word. You missed the bit later on - Chris Brumme again: quote Chris Brumme said: I just got the official word from the WinForms team. It is not necessary to call Control.EndInvoke. You can call BeginInvoke in a "fire and forget" manner with impunity. May 12, 2003 5:30 PM /quote I know it's on a blog rather than being part of the documentation, but I think it's still reasonably definitive. Let's say I trust Chris Brumme when it comes to this kind of thing ![]() |
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
| |