![]() | |
![]() |
| | Thread Tools | Search this Thread | Display Modes |
#1
| |||
| |||
|
#2
| |||
| |||
|
|
BeginInvoke returns an IAsyncResult, but in cases where the caller doesn't care and couldn't do anything even if it did care, I don't assign the returned value and assumed it would be garbage-collected. Some bloggers say that this pattern leaks resources. |
#3
| |||
| |||
|
|
Norman Diamond <ndiamond (AT) community (DOT) nospam> wrote: BeginInvoke returns an IAsyncResult, but in cases where the caller doesn't care and couldn't do anything even if it did care, I don't assign the returned value and assumed it would be garbage-collected. Some bloggers say that this pattern leaks resources. In principle, it might at least *temporarily* leak resources. It depends on the implementation. However, the Windows Forms team has guaranteed that Control.BeginInvoke doesn't need a matching EndInvoke call. |
|
If you want "fire and forget" semantics you can use the class implemented here: http://www.yoda.arachsys.com/csharp/...readpool.shtml |
#4
| |||
| |||
|
|
"Jon Skeet [C# MVP]" <skeet (AT) pobox (DOT) com> wrote in message In principle, it might at least *temporarily* leak resources. It depends on the implementation. However, the Windows Forms team has guaranteed that Control.BeginInvoke doesn't need a matching EndInvoke call. Thank you for responding, but I'm having trouble figuring out the answer(s). In principle there might be resource leaks which might be at least temporary, which means there's a chance the leaks might grow until the process exits? So some bloggers are correct and MSDN (at least the two pages which I cited last time) is wrong? However, Control.BeginInvoke doesn't need a matching EndInvoke call for which reason: because there is no leak, or because the leak is temporary until garbage collection, or the leaks accumulate until the process exits but luckily no one (including me so far) has been damaged by the leaks accumulating too enormously? |
#5
| ||||
| ||||
|
|
In principle, it might at least *temporarily* leak resources. It depends on the implementation. However, the Windows Forms team has guaranteed that Control.BeginInvoke doesn't need a matching EndInvoke call. Thank you for responding, but I'm having trouble figuring out the answer(s). In principle there might be resource leaks which might be at least temporary, which means there's a chance the leaks might grow until the process exits? So some bloggers are correct and MSDN (at least the two pages which I cited last time) is wrong? |
|
However, Control.BeginInvoke doesn't need a matching EndInvoke call for which reason: because there is no leak, or because the leak is temporary until garbage collection, or the leaks accumulate until the process exits but luckily no one (including me so far) has been damaged by the leaks accumulating too enormously? |
|
If you want "fire and forget" semantics you can use the class implemented here: http://www.yoda.arachsys.com/csharp/...readpool.shtml Thank you. But I still don't understand: do I *need* the class that is implemented there? |
|
Again, in my situation I'm calling BeginInvoke on a private method in a form, so the callee is running in the UI thread and if any errors occur that's the time they're displayed. The caller is in a background thread which is about to exit, it cannot do anything with a return value or any other information, so "fire and forget" is suitable. |
#6
| |||
| |||
|
|
Norman Diamond <ndiamond (AT) community (DOT) nospam> wrote: In principle, it might at least *temporarily* leak resources. It depends on the implementation. However, the Windows Forms team has guaranteed that Control.BeginInvoke doesn't need a matching EndInvoke call. Thank you for responding, but I'm having trouble figuring out the answer(s). In principle there might be resource leaks which might be at least temporary, which means there's a chance the leaks might grow until the process exits? So some bloggers are correct and MSDN (at least the two pages which I cited last time) is wrong? It's likely that finalizers will free up the resources, so they don't leak as such (assuming things have been robustly implemented, of course) - but the resources they temporarily hold might be required *before* the finalizer is executed. However, Control.BeginInvoke doesn't need a matching EndInvoke call for which reason: because there is no leak, or because the leak is temporary until garbage collection, or the leaks accumulate until the process exits but luckily no one (including me so far) has been damaged by the leaks accumulating too enormously? BeginInvoke is implemented in Windows Forms has been implemented in such a way that there's no leak, in my understanding. If you want "fire and forget" semantics you can use the class implemented here: http://www.yoda.arachsys.com/csharp/...readpool.shtml Thank you. But I still don't understand: do I *need* the class that is implemented there? That depends on whether you're using Control.BeginInvoke or a delegate BeginInvoke. Again, in my situation I'm calling BeginInvoke on a private method in a form, so the callee is running in the UI thread and if any errors occur that's the time they're displayed. The caller is in a background thread which is about to exit, it cannot do anything with a return value or any other information, so "fire and forget" is suitable. If you're using Control.BeginInvoke, you don't need to worry. -- Jon Skeet - <skeet (AT) pobox (DOT) com http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk |
#7
| ||||
| ||||
|
|
OK, I think this makes things clearer. |
).|
Calling BeginInvoke on an "ordinary" delegate, without calling EndInvoke, can cause resource usages to hang around longer than necessary (until the next garbage collection), which can cause temporary starvation in a server or other victim when a heavy user of resources is present. However, there's no permanent leak. Calling BeginInvoke on Control, without calling EndInvoke, doesn't even have that problem. |
|
There are 8,192 executions of BeginInvoke in the situation I'm presently concerned with, so I think that temporary starvation isn't happening, and nothing worse can happen. |
|
I still have some curiosity remaining from a former not-having-a-life as a language lawyer. When I create a delegate that points to a private method in a form, the form inherits from Control. But how is that enough to make the delegate know whether to be a Control.something (with method Control.BeginInvoke) or an "ordinary" delegate (with method somethingelse.BeginInvoke)? |
#8
| ||||
| ||||
|
|
even if you can show in the current Control implementation that there's no harm in not calling Control.EndInvoke(), I would say that absent some clear, explicit statement in the MSDN documentation pages that says that you don't need to call EndInvoke(), that pairing the two calls may well be important, and very much _should_ be assumed to be so, |
|
One feature of delegates is that they are not specific to whatever method they might be passed to. You can create a single delegate that is suitable for either Control.BeginInvoke() or Delegate.BeginInvoke() (and for the synchronous Invoke() equivalents as well). |
|
If you call Control.BeginInvoke(), then it's used by Control.BeginInvoke(), executed on that Control instance's owning thread. If you call Delegate.BeginInvoke() on the delegate instance itself, then it's invoked asynchronously via that method. |
|
On Wed, 26 Dec 2007 16:21:11 -0800, Norman Diamond ndiamond (AT) community (DOT) nospam> wrote: OK, I think this makes things clearer. Good, my turn to confuse matters (i.e. create a mess that Jon has to clean up ).Calling BeginInvoke on an "ordinary" delegate, without calling EndInvoke, can cause resource usages to hang around longer than necessary (until the next garbage collection), which can cause temporary starvation in a server or other victim when a heavy user of resources is present. However, there's no permanent leak. Calling BeginInvoke on Control, without calling EndInvoke, doesn't even have that problem. The first paragraph is correct for sure. I remain unconvinced that it's untrue for Control.BeginInvoke(), at least as an unqualified statement. Consider the statement in the doc page for IAsyncResult.AsyncWaitHandle: Notes to Implementers The object that implements IAsyncResult does not need to create the WaitHandle until the AsyncWaitHandle property is read. It is the choice of the IAsyncResult implementer. However, if the implementer creates AsyncWaitHandle, it is the responsibility of the implementer to signal the WaitHandle that will terminate the wait at the appropriate time. For example, System.Runtime.Remoting.Messaging.AsyncResult terminates the wait on behalf of the caller when an asynchronously invoked method returns. Once created, AsyncWaitHandle should be kept alive until the user calls the method that concludes the asynchronous operation. At that time the object behind AsyncWaitHandle can be discarded. In other words, if the caller to Control.BeginInvoke() actually uses the AsyncWaitHandle from the IAsyncResult it gets from Control.BeginInvoke(), then that WaitHandle (which implements IDisposable and so must be disposed when it's no longer needed) is required to be kept until the "_user_ [emphasis mine] calls the method that concludes the asynchronous operation". In other words, the user's code has every reason to expect that the WaitHandle will remain valid until that code calls Control.EndInvoke(). So code that gets the AsyncWaitHandle is going to have to call EndInvoke() to ensure they clean up that resource properly (EndInvoke() baing "the method that concludes the asynchronous operation". Beyond that, even if you can show in the current Control implementation that there's no harm in not calling Control.EndInvoke(), I would say that absent some clear, explicit statement in the MSDN documentation pages that says that you don't need to call EndInvoke(), that pairing the two calls may well be important, and very much _should_ be assumed to be so, at least if your code uses the AsyncWaitHandle in the IAsyncResult, if not in other cases. I've looked for such a clear, explicit statement and haven't been able to find one. I'm carefully ignoring the fact that Control.BeginInvoke() doesn't follow the normal pattern for async methods. There's no way to specify a callback, never mind a context/state object for the callback. This means it's practically impossible for the asynchronously invoked method to have access to the IAsyncResult (it's not literally impossible, but it's impractical because any attempt to provide access results in a race condition...that can be addressed by adding thread synchronization, but then that seems to me to negate the whole point of using BeginInvoke() in the first place). This means that if you _do_ call EndInvoke() you have to do it somewhere other than the invoked delegate. This leads to inelegant things like polling IAsyncResult.IsCompleted, or just calling EndInvoke() and possibly getting blocked anyway. I suppose there are situations where this is actually what you'd want to do, but being forced into seems kind of ugly to me. In other words, it bugs me that the whole Control.BeginInvoke() API is the way it is. While I can understand the need for backward compatibility, I don't understand why it remains in this sort of awkward state rather than adding some overloads to Control.BeginInvoke() to allow it to be used in a more typical fashion. There are 8,192 executions of BeginInvoke in the situation I'm presently concerned with, so I think that temporary starvation isn't happening, and nothing worse can happen. I suspect that as long as you do nothing with the IAsyncResult returned by BeginInvoke(), you're fine. But I wish there was some more explicit documentation to that effect. I still have some curiosity remaining from a former not-having-a-life as a language lawyer. When I create a delegate that points to a private method in a form, the form inherits from Control. But how is that enough to make the delegate know whether to be a Control.something (with method Control.BeginInvoke) or an "ordinary" delegate (with method somethingelse.BeginInvoke)? One feature of delegates is that they are not specific to whatever method they might be passed to. You can create a single delegate that is suitable for either Control.BeginInvoke() or Delegate.BeginInvoke() (and for the synchronous Invoke() equivalents as well). The delegate does not need to be related to the Control class at all, never mind be an instance member, or a member of any Control-derived class of any sort. The corollary is that the delegate itself doesn't "know whether to be" anything in particular, nor does it need to. The sole determining factor is how you use it If you call Control.BeginInvoke(), then it's used by Control.BeginInvoke(), executed on that Control instance's owning thread. If you call Delegate.BeginInvoke() on the delegate instance itself, then it's invoked asynchronously via that method. Pete |
#9
| ||||
| ||||
|
|
Yeah, present some clear, explicit examples isn't enough. And with our knowledge of MSDN, even present some clear, explicit statement might not be enough either. |
|
EndInvoke would impose an unnecessary delay on the background thread where I call BeginInvoke. The more I think about it, there's a tiny chance that I have a race condition now, and if I do then it might be minimizable by making the UI thread sleep a few milliseconds. If the background thread gets delayed and causes a race condition then there's no solution at all. EndInvoke would only magnify it. |
|
My copy of MSDN doesn't have Delegate.BeginInvoke. It has Delegate.DynamicInvoke. I thought C#'s delegate.Invoke and delegate.BeginInvoke were fictions invented by the C# compiler, calling some .Net stuff which I haven't quite figured out yet. |

|
Since I'm a Form and I call this.BeginInvoke on the delegate, I'm safely calling Control.BeginInvoke, right? Ugh, that needs clarification. I'm a Form, but one of my methods can be called by a background thread. This is where I have to BeginInvoke my own other method that operates on me, and return immediately to the background thread who called me. |

#10
| |||
| |||
|
|
My copy of MSDN doesn't have Delegate.BeginInvoke. It has Delegate.DynamicInvoke. I thought C#'s delegate.Invoke and delegate.BeginInvoke were fictions invented by the C# compiler, calling some .Net stuff which I haven't quite figured out yet. |
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
| |