IDisposable, ObjectDisposedException, and threadsafe types
Asked Answered
D

4

6

Is there any point in keeping track of the classic bool disposed field on an otherwise threadsafe type for the purposes of conditionally throwing an ObjectDisposedException at the beginning of all primary exposed methods?

I've seen this pattern recommended in a few places online but I'm not sure if the authors are using it correctly, so this question assumes that they are.

In such a scenario, it seems that the only way to ensure that the disposed condition is true beyond the condition's evaluation is to use a synchronization mechanism such as lock() over the entire body of each exposed member including the Dispose(bool) method. Wouldn't this make the type effectively single-threaded again?

And if this is true, then there'd be no point in using it, and therefore you can't rely on the ObjectDisposedException mechanism in some IDisposable implementations - so then why would we EVER employ this mechanism if it isn't necessary?

====

I guess IDisposable and ObjectDisposedException just don't go together for thread-safe types.

Displant answered 11/2, 2010 at 18:28 Comment(1)
See also: #170528Displant
I
4

Perhaps a more efficient way of making a threadsafe object not become disposed while a method is running is to use a ReaderWriterLockSlim. Have all the public methods obtain a read lock while executing and release it when they're done. Have Dispose obtain a writer lock. It will wait till all the other methods are done before it obtains it's write lock. It then sets isDisposed inside the write lock which it exclusively holds. Any calls to public methods after Dispose is done can see isDisposed and throw the ObjectDisposedException.

ReaderWriterLockSlim

http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

Indeterminable answered 11/2, 2010 at 18:39 Comment(4)
Cool idea. Got a sample? Not finding documentation on ReaderWriterSlimLock. Is this something you've seen before or something you've just brainstormed?Displant
Just brainstorming, but I think it should work well for your request. I misspelled it in my original answer, it's ReaderWriterLockSlim. I added a link to MSDN docs.Indeterminable
Actually, that almost works, except that FXcop rightly points out that ReaderWriterLockSlim implements IDisposable and should be disposed along with the rest of the object's resources. So once dispose is called, I would no longer be able to get a read lock in order to test if the object has been disposed or not.Displant
I don't consider this question closed, but this was a good attempt and I don't want to leave the question open.Displant
A
3

If the behavior of your object will be different if it is already disposed, and if it's likely that it will be used after it's been disposed, then you need to keep track of this. It's better to throw ObjectDisposedException than to throw whatever random exception that will occur if the object is already disposed and you don't check first.

Anthracene answered 11/2, 2010 at 19:14 Comment(1)
Yes, but this question is about how to throw an ObjectDisposedException with certainty in a multi-threaded scenario.Displant
O
0

Given that the "Disposed" boolean is only updated in one place, and it is a bug in your caller to use the object after they had called Disposed.

I think it is good enough to throw ObjectDisposedException "most of the time" after Dispose has been called. I see ObjectDisposedException as being a debug helper not thingthing that a caller should be catching.

Owlet answered 19/8, 2010 at 8:35 Comment(0)
E
0

If there is a possibility of a method being called while an object is disposed, the method's semantics should be defined in such a way that calling it on a disposed object will pose no problem. In cases where there may or may not be a problem, one should use the "try/do" pattern. If Microsoft had followed this principle with Control.BeginInvoke, there would be both a "Control.BeginInvoke" and a "Control.TryBeginInvoke"; the latter would be explicitly defined as returning false and doing nothing if a control was disposed prior to the action being enqueued (note that Control.BeginInvoke returning true would not guarantee that the control wouldn't get disposed before the action was actually run). This pattern would be very useful in things like display-update scenarios: if a control isn't disposed, I want its update routine to run; if it gets disposed before the update routine runs, however, the update will become moot and its failure to run would hardly be a problem.

Enterprise answered 29/7, 2011 at 20:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.