Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / April 2008

Tip: Looking for answers? Try searching our database.

ReaderWriterLockSlim + Dispose?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
NvrBst - 05 Apr 2008 00:33 GMT
One last question today :)  Most locks I've used never had a Dispose
(Monitor, ReaderWriterLock, etc).  Looking at the
ReaderWriterLockSlim's Dispose method its just cleaning up some
Threading.WaitHandle's.

Whenever I see a Dispose method I always want to call it after I'm
done with the object.  All examples I've ever found online don't use
dispose with the ReaderWriterLockSlim.  Making my classes that use
this lock IDisposable for this reasion alone is a little frustrating,
and makes the implementation a little harder (since I have to
constantly check to see if the locks disposed, mainly when using it
with a thread pool).

Since only WaitHandles are getting closed, the GC will eventually
clean them if I ignore the Disposing on the ReaderWriterLockSlim?  Is
there performance increases in using the disposable WaitHandles vs how
other locks without Dispose() do it?

Thanks :)  I'm mostly just curious.

NB
Peter Duniho - 05 Apr 2008 01:11 GMT
> One last question today :)  Most locks I've used never had a Dispose
> (Monitor, ReaderWriterLock, etc).  Looking at the
> ReaderWriterLockSlim's Dispose method its just cleaning up some
> Threading.WaitHandle's.

Why do you write "just"?  I would guess that for most classes that  
implement IDisposable, they "just" clean up some things.  Are you implying  
that the ReaderWriterLockSlim.Dispose() is less important than for other  
classes that implement IDisposable?

> Whenever I see a Dispose method I always want to call it after I'm
> done with the object.

Yes.

> All examples I've ever found online don't use
> dispose with the ReaderWriterLockSlim.

Do you mean that the examples use ReaderWriterLockSlim but don't dispose  
it when the code is done with it?  That's a bug.

> Making my classes that use
> this lock IDisposable for this reasion alone is a little frustrating,
> and makes the implementation a little harder (since I have to
> constantly check to see if the locks disposed, mainly when using it
> with a thread pool).

I don't understand why it's a problem.  Why do you have to check to see if  
the lock is disposed?  Why would it be disposed unless you're sure you're  
done with it (i.e. your own Dispose() method has been called)?

> Since only WaitHandles are getting closed, the GC will eventually
> clean them if I ignore the Disposing on the ReaderWriterLockSlim?

Not necessarily.  If the finalizer thread gets around to running, they  
will eventually get cleaned up, yes.  But there's no guarantee that this  
will ever happen, or when it will happen.  You should not design code that  
relies on that (other than implementing your own finalizer, of course).

> Is
> there performance increases in using the disposable WaitHandles vs how
> other locks without Dispose() do it?

It seems to me that the main difference is one of functionality.  
ReaderWriterLockSlim serves a very specific purpose.  If you have need for  
that purpose, you are likely going to need some disposable synchronization  
object anyway, so using a lock implementation instead that itself needs  
disposing doesn't make things any worse with respect to disposal, but of  
course simplifies your life in that you don't have to reimplement all the  
stuff in ReaderWriterLockSlim.

If you don't need the added functionality that ReaderWriterLockSlim  
provides, then you might as well use one of the simpler, non-disposable  
synchronization techniques.  Alternatively, you could use the older  
ReaderWriterLock class, and accept the additional performance overhead it  
has.

Pete
NvrBst - 05 Apr 2008 05:22 GMT
On Apr 4, 5:11 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> Are you implying  
> that the ReaderWriterLockSlim.Dispose() is less important than for other  
> classes that implement IDisposable?

Hehe, aye, that was my question.  For example, if it was a file, and
others are potentially wanting to use the file, then I'd rank high on
"definally dispose when your done".  But I've never really worked with
these "WaitHandles".  Are they low priority to close?  Does the OS
just create new ones when people request them, so it doesn't matter
even a little bit if the one ReaderWriterLockSlim is using isn't
closed for a few mins after its done with it?  I only see a memory
potential problem here, but its not like WaitHandles are images, no
one really cares about a few bytes till GC collects it (unless its in
some kind of loop).  Again, I could be wrong, which is why I'm asking,
basically what I'm missing.

> Do you mean that the examples use ReaderWriterLockSlim but don't dispose  
> it when the code is done with it?  That's a bug.

http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx
http://msdn2.microsoft.com/en-us/library/bb355025.aspx
http://www.bluebytesoftware.com/blog/PermaLink,guid,c4ea3d6d-190a-48f8-a677-44a4
38d8386b.aspx


To name a few.  The 1st MSDN example displays the entire class with no
dispose in it.  If you google / google code search
"ReaderWriterLockSlim" I don't think you'll be able to find a code
snipplet or example that uses dispose with RWLS, which I found very
strange.  This made me believe that there is something I'm missing?
Possible responsing I might of been expecting after posting was stuff
like:

"Ahh, its because all those examples are used in the main object,
where 99.9% of locks are used.  Since the application closes when your
done with the object, that uses the RWLS, no one worries about using
the dispose method for RWLS.  Its just correctness for the other 0.1%
of the time someone might be using it in a class that gets created
thousands of times, and thus may want to clean it up after its done.".

Or maybe a "Its a new class so people havn't learned how to use it
correctly yet, I'd highly suggest always calling the Dispose, even if
its in your main object; YOU DEFINALLY DON'T WANT THOSE WAITHANDLES
FLOATING AROUND ANYLONGER THAN YOU HAVE TOO".

Basically, for example, every code snipplet/example on say
StreamReader has the Dispose method with it, why doesn't
ReaderWriterLockSlim?

> I don't understand why it's a problem.  Why do you have to check to see if  
> the lock is disposed?  Why would it be disposed unless you're sure you're  
> done with it (i.e. your own Dispose() method has been called)?

There are reasions.  For example, if your sychronizing a thread pool
with RWLS's, then you can't do something like "stop all theads, its
time to clean up" that I know of.  A real life example could be, say
your making a macroing program.  Its designed to run multiple macros
at the same time and are using the thread pool.  Even if you know 5
macros are running (maybe in constant loops), it's time to clean up or
shut down, you don't know how long they are going to take.  Since the
client made the macro(script) it could be doing some kind of huge loop
and don't want to wait for it.  Cleaning up could result in that
thread trying to use the lock, which is annoying in the case of RWLS-
if its the only disposable thing in the application.  With the thread
pool, any situation you don't want to wait for the threads to finish
before cleaning up could result in crashes if you don't check if the
lock is disposed before acquiring it.

Yes yes, you probably don't want to use the thread pool in that type
of situation, but not knowing when the threads are going to be done is
somewhat common, even if you did know you don't always want to wait
around for it to finish (expecially in the case of a thread pool where
you can't interrupt/abort it, and who knows how long till it checks
for a stop variable).

> Not necessarily.  If the finalizer thread gets around to running, they  
> will eventually get cleaned up, yes.  But there's no guarantee that this  
> will ever happen, or when it will happen.  You should not design code that  
> relies on that (other than implementing your own finalizer, of course).

Which was another question.  Does it really matter if these
"WaitHandles" don't get cleaned up for a while?  How does it affect
other things if at all? (Other than maybe some memory that lingering
till GC Collects / AppDomain unloads?).  I don't see these WaitHandles
being very big though memory wize though.

> [...] If you don't need the added functionality that ReaderWriterLockSlim  
> provides, then you might as well use one of the simpler, non-disposable  
> synchronization techniques.  Alternatively, you could use the older  
> ReaderWriterLock class, and accept the additional performance overhead it  
> has.

I was thinking maybe the other implementations use WaitHandles and
just don't clean them up?  How many ways can there be for locks to
wait on an event :)  Hehe, my last posts last paragraph was more so
asking this question.  IE Maybe RWSL, without disposing, is very close
to how Monitor works. It might not be but I was also fishing for any
type of information with locks with the statment ;)

:) Thanks for the comments, I'm still a little curious on information
though about the topic.
Peter Duniho - 05 Apr 2008 06:28 GMT
>> Do you mean that the examples use ReaderWriterLockSlim but don't  
>> dispose  
>> it when the code is done with it?  That's a bug.
>
> http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

Well, as you probably can guess...I think this sample is incomplete, if  
not buggy.

> http://msdn2.microsoft.com/en-us/library/bb355025.aspx

This example stores the instance in a static variable, so IDisposable  
wouldn't apply.

> http://www.bluebytesoftware.com/blog/PermaLink,guid,c4ea3d6d-190a-48f8-a677-44a4
38d8386b.aspx

This doesn't even include compilable code, so I'd hardly say you should  
expect it to be complete.  Lack of any specific code, IDisposable  
implementation or otherwise, shouldn't be in any way inferred to mean it  
can be left out in real code.

> To name a few.  The 1st MSDN example displays the entire class with no
> dispose in it.  If you google / google code search
> "ReaderWriterLockSlim" I don't think you'll be able to find a code
> snipplet or example that uses dispose with RWLS, which I found very
> strange.  This made me believe that there is something I'm missing?

I can't say whether you're missing something.  I do know that a quick  
Google search yielded this link:
http://blogs.msdn.com/vancem/archive/2006/03/29/564854.aspx

Check out the comments starting with Bill Menees's first comment.  It  
doesn't pertain to ReaderWriterLockSlim per se, but it does perhaps give  
some insight as to why a class might have disposable stuff in it but not  
implement IDisposable, or why a class that does implement IDisposable  
might be considered "safe" to not dispose of.

I'm not saying it's an answer as to why you shouldn't dispose  
ReaderWriterLockSlim.  I'm still of the opinion that a class that  
implements IDisposable should be disposed of when you're done.  But not  
everyone is necessarily going to agree with my viewpoint.

> [...]  Since the
> client made the macro(script) it could be doing some kind of huge loop
[quoted text clipped - 4 lines]
> before cleaning up could result in crashes if you don't check if the
> lock is disposed before acquiring it.

I still don't see the problem.  For me, it's a fundamental problem for you  
to start cleaning stuff up before things are done with them.  In your  
example, why does the lock exist?  Presumably, to ensure that the multiple  
macro-processing threads are properly synchronized with each other.  So if  
you dispose that lock before those threads are done, and the threads  
simply avoid taking the lock if it's been disposed, now you have a  
situation in which the threads aren't synchronized.

If that's safe now, it was safe before and you didn't need the lock.  If  
it's not safe, then your decision to clean stuff up without terminating  
the threads created a synchronization bug.  Either way, that's showing us  
that the hypothetical design is wrong in the first place.  It's not an  
example of why disposing a lock class is a problem.

In that particular example, you either need to decide whether you're going  
to interrupt the threads that need the lock, or you're going to delay  
cleanup of the lock until the threads are all done.  You can't let the  
threads run _and_ clean up the lock right away.

> [...]
> Which was another question.  Does it really matter if these
> "WaitHandles" don't get cleaned up for a while?  How does it affect
> other things if at all? (Other than maybe some memory that lingering
> till GC Collects / AppDomain unloads?).  I don't see these WaitHandles
> being very big though memory wize though.

Well, generally speaking, it's not so much the size of the object as it is  
the size of the OS data structures that track the object.  I suspect that  
these issues are _much_ alleviated since the old 16-bit Windows days.  
However, the OS does continue to provide dispose semantics for these  
objects, and I think it's unwise to make any assumptions that they are  
optional.

Could you get away with it?  Probably.  The fact is, a lot of these sorts  
of things only wind up biting you some small fraction of the time you  
ignore them.  But that doesn't mean it's generally acceptable design to do  
so.  If anything, it's why you should _always_ be careful to follow the  
conventions imposed on you by the design, because it can be really  
difficult to reproduce potential problems at will.  This means the  
problems often come up when you are least prepared or able to deal with  
them.

> I was thinking maybe the other implementations use WaitHandles and
> just don't clean them up?  How many ways can there be for locks to
> wait on an event :)

Well, not all synchronization objects use events.  Now, whether it's  
possible to write a synchronization object without using _any_ disposable  
unmanaged resources, I can't personally say.  But inasmuch as managed code  
runs with the complete support of the .NET run-time, it seems plausible to  
me that there could be synchronization objects that have no need of being  
disposed.

> [...]
> :) Thanks for the comments, I'm still a little curious on information
> though about the topic.

And I hope you get them.  I agree that getting more details on the  
specifics would be useful and interesting.

But I'm still going to suggest that you always dispose classes that  
implement IDisposable.  :)  It's one thing for the authors of .NET, who  
have intimate knowledge with the inner workings of the run-time and the  
framework, to make a choice to not implement IDisposable even though a  
class might benefit from it.  It's yet another for the rest of us to make  
decisions contrary to the accepted conventions exposed by .NET.  You do so  
at your own peril.  :)

Pete
NvrBst - 05 Apr 2008 19:17 GMT
On Apr 4, 10:28 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> I can't say whether you're missing something.  I do know that a quick  
> Google search yielded this link:http://blogs.msdn.com/vancem/archive/2006/03/29/564854.aspx

:)  I did see that page before when searching "RWLS + dipose", it was
the only page that showed up on the first google results page that had
relavance. Aye, its not the ReaderWriterLockSlim class, but the
comments at the bottom did give me suspecions that cleaning up RWLS's
might not be needed that much.

> In that particular example, you either need to decide whether you're going  
> to interrupt the threads that need the lock, or you're going to delay  
> cleanup of the lock until the threads are all done.  You can't let the  
> threads run _and_ clean up the lock right away.

Aye.  I understand this design wise, but, in the case of the thread
pool, you can't interrupt it.  And waiting around for the threads to
finish isn't always a perferred solution; maybe the locks were there
to syncronize actions (IE in the case of a chat program, the thread
could lock the send/recive method on a line basis, so if you stop
locking the worst that could happen would be something like Msg1:
"hello jim."  Msg2: "test", resulting in "hetleslo jim .\nt".  If your
cleaning up, your probably not caring what else the threads going to
do as long as it doesn't crash, etc.

> This example stores the instance in a static variable, so IDisposable
> wouldn't apply.

Ahh.  I always through using static on IDisposable objects was a no
no.  But yes, I see now that if the IDisposable object is living to
the end of the application (which is the case of my RWLS's usally),
making them static would simplify my code a lot, and might be the
intended way of using them most the time.  I'll look into this
approach more at the very least :)

Thanks for your comments, they were helpful.  I usally use Monitor's
(+lock statments) anyway, but wanted to try a few applications with
RWLS and think static might be the way to go for some of the problems
I had with them.

NB
Peter Duniho - 05 Apr 2008 22:46 GMT
> [...]
>> In that particular example, you either need to decide whether you're  
[quoted text clipped - 5 lines]
> Aye.  I understand this design wise, but, in the case of the thread
> pool, you can't interrupt it.

Of course you can.  Not that I was suggesting you use Thread.Abort(), but  
even that should work okay (exceptions are eaten by the thread pool, but  
your own code is aborted...the thread pool will just create a new thread  
later if needed).  In reality, if you need a thread (thread pool or  
otherwise) to be interruptible, you just design it to be so.  Use a  
volatile flag, have the code in the thread check the flag and exit when it  
can.  Or any of a number of other signaling mechanisms that are available.

> And waiting around for the threads to
> finish isn't always a perferred solution;

If not, then you need to design the thread to be interruptible.  That's  
not a problem.

> maybe the locks were there
> to syncronize actions (IE in the case of a chat program, the thread
> could lock the send/recive method on a line basis, so if you stop
> locking the worst that could happen would be something like Msg1:
> "hello jim."  Msg2: "test", resulting in "hetleslo jim .\nt".

If I were using a messaging application that produced a result like that,  
I would never ever run it again.  At the very least, it suggests that the  
provider of that application was willing to let less-than-perfect behavior  
occur just to make their own life simpler.  And worst, it's a strong clue  
that the provider may have underestimated the need to produce correct code.

Synchronization exists to ensure correct, predictable behavior from the  
code.  If the code isn't synchronized and is allowing output to be  
intermingled when that wasn't part of the user's intent, who knows what  
else may have been overlooked by the provider?

> If your
> cleaning up, your probably not caring what else the threads going to
> do as long as it doesn't crash, etc.

Well, first of all...the "as long as it doesn't crash" is an important  
consideration: how can you prove that your code won't crash if you've  
abandoned synchronization?  Secondly, if you're cleaning up, then either  
it's okay to interrupt the threads or it's not.  If it is, then you design  
those threads so that they can be interrupted and then you interrupt  
them.  If it's not, then you have no choice but to wait for them to  
finish.  What benefit is there in doing some of the cleanup early, and  
then still waiting on the threads?  Especially when that cleanup removes  
objects that the threads need to use?

Pete
NvrBst - 06 Apr 2008 00:01 GMT
On Apr 5, 2:46 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > [...]
> >> In that particular example, you either need to decide whether you're  
[quoted text clipped - 52 lines]
>
> Pete

I was talking about the Managed ThreadPool, not a custom made one; the
one you usally access with "ThreadPool.QueueUserWorkItem(...)".  After
you start a thread on the threadpool then you can't stop it without a
volatile flag.  Maybe you could have the work items list themselves
someplace static so you could call abort from another thread, but I'm
not sure if its possible.

>  What benefit is there in doing some of the cleanup early, and
> then still waiting on the threads?  Especially when that cleanup removes
> objects that the threads need to use?

I can only list situations off the top of my head (which are quick
examples).  I'm sure people run into better (more relivant) situations
naturally, but for example say you want to Restart
(Application.Restart()) the application, or do something else (in the
case of some kind of error, or special event), the user may very of
well been the one to signal the "okay get on with it, I don't care
what threads are doing I want to do something else now", then the user
surly doesn't want to wait for any threads, so you clean up what you
can really quick, set the violet flag to tell the threads to finish,
and start the next task (letting the threads finish gracefully in the
background).

> If not, then you need to design the thread to be interruptible.  That's
> not a problem.

Sometimes, for quick applications at least, re-designing your own
ThreadPools, or such, to fit your situtation perfectly isn't
acceptable (time wise).  Instead they use the one already made and
live by the limitations of that implementation, or work around them.

NB
Peter Duniho - 06 Apr 2008 04:00 GMT
> I was talking about the Managed ThreadPool, not a custom made one;

So was I.

> the
> one you usally access with "ThreadPool.QueueUserWorkItem(...)".  After
> you start a thread on the threadpool then you can't stop it without a
> volatile flag.

You can call Thread.Abort() on one of those threads as easily as on any  
other thread, provided you have a reference to the thread.  You can always  
get a reference to the thread by getting Thread.CurrentThread inside the  
worker thread.

> Maybe you could have the work items list themselves
> someplace static so you could call abort from another thread, but I'm
> not sure if its possible.

Yes, it's possible.  And it's exactly what you'd have to do, should you  
decide to use Thread.Abort() to interrupt the thread.

Personally, I feel that using Thread.Abort() is a bad idea, and it's not  
what I was suggesting you might do.  But it certainly is possible.

>>  What benefit is there in doing some of the cleanup early, and
>> then still waiting on the threads?  Especially when that cleanup removes
>> objects that the threads need to use?
>
> I can only list situations off the top of my head (which are quick
> examples).

Such as?  Do you have an example of a scenario in which there's a benefit  
of doing some cleanup early, removing objects that the threads need to  
use, and then still waiting on the threads to complete?

> I'm sure people run into better (more relivant) situations
> naturally, but for example say you want to Restart
[quoted text clipped - 6 lines]
> and start the next task (letting the threads finish gracefully in the
> background).

But that's not a correct design, if the threads may want to use any of the  
data structures you are cleaning up before they complete.

You could certainly design an application such that the entire context for  
a session is replaced when restarting, where none of the previous context  
is cleaned up until the threads are done.  But then you're basically  
waiting for the threads to finish anyway, which is what I said you need to  
do.

You simply cannot have valid code in which you clean up data structures  
that threads that continue to run may need to use.  Your only choices are  
to wait for the threads to complete before cleaning up the data structures  
(either letting them run to completion or telling them to interrupt  
themselves), or to change the design so that those data structures are not  
needed by the threads.

Any other design is flawed.

>> If not, then you need to design the thread to be interruptible.  That's
>> not a problem.
>
> Sometimes, for quick applications at least, re-designing your own
> ThreadPools, or such, to fit your situtation perfectly isn't
> acceptable (time wise).

Irrelevant.  That's not what I'm suggesting anyone do.

> Instead they use the one already made and
> live by the limitations of that implementation, or work around them.

I don't feel that a coder really has a choice with respect to writing  
correct code.  No programmer deserving of that label has any business  
intentionally writing code that they know to be defective.

Pete
NvrBst - 06 Apr 2008 19:01 GMT
On Apr 5, 8:00 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > I was talking about the Managed ThreadPool, not a custom made one;
>
[quoted text clipped - 77 lines]
>
> Pete

Correct code is in the eye of the beholder.  Just because your design
has some limitations or work-arounds doesn't make it defective.

> But that's not a correct design, if the threads may want to use any of the
> data structures you are cleaning up before they complete.

Who says the threads want to use any of the data structures you are
clenaing up.  Furthermore, there is a "disposed" at their disposal.
if(!disposed) use structure.

I always read that ThreadPool threads are lightweight; using them like
suggested isn't correct (design wise as you say).  If someone is using
it like that then they probably should redesign the solution to not
use the ThreadPool :P

NB
Peter Duniho - 06 Apr 2008 19:20 GMT
> Correct code is in the eye of the beholder.  Just because your design
> has some limitations or work-arounds doesn't make it defective.

Just because some correct code has some limitations or work-arounds, that  
does not mean that all code with some limitations or work-arounds is not  
defective.

>> But that's not a correct design, if the threads may want to use any of  
>> the
>> data structures you are cleaning up before they complete.
>
> Who says the threads want to use any of the data structures you are
> clenaing up.

You did.  You specifically said you are talking about cleaning up  
synchronization data structures that are used by the threads.

> Furthermore, there is a "disposed" at their disposal.
> if(!disposed) use structure.

If they have the option of not using the structure, then they don't need  
the structure.  In which case you should not have the structure at all.

Conversely, if they need the structure, then you don't have the option of  
them not using the structure when it's been disposed.

> I always read that ThreadPool threads are lightweight; using them like
> suggested isn't correct (design wise as you say).  If someone is using
> it like that then they probably should redesign the solution to not
> use the ThreadPool :P

This has nothing at all to do with whether you are using the thread pool  
or some other mechanism.  And I have no idea what you mean by "using them  
like suggested isn't correct".  Using them as _who_ suggested?  What  
suggestion is it that you feel isn't correct?

Not that the answer to that question would have any relevance to the issue  
I'm writing about in this thread.  But your paragraph is amibguous and I'm  
curious what you actually meant.

Pete
NvrBst - 06 Apr 2008 19:39 GMT
On Apr 6, 11:20 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> You did.  You specifically said you are talking about cleaning up  
> synchronization data structures that are used by the threads.

I think you miss read some place, I've never used the word data
structures anywhere here, I said sychronizing actions with the chat
program example if you thought that's the same thing.

> If they have the option of not using the structure, then they don't need  
> the structure.  In which case you should not have the structure at all.

"They don't need the structure anymore" is what should be said, this
does not mean they didn't need it before the event that signled the
clean up.

> Not that the answer to that question would have any relevance to the issue  
> I'm writing about in this thread.  But your paragraph is amibguous and I'm  
> curious what you actually meant.

> Any other design is flawed.

I walk talking about this.  To be more specific, basically I said that
if I have a solution that cleans up the object immediatly, lets all
the threads gracefully exit on their own, and doesn't affect the user
(visually) any bit, then not only is this a correct design, but its
more elegant in the respect of using the "disposed" variable as a
violet flag (which, intuativaly, gets checked - and can immidatly exit
the thread when it is checked and found violet).

If the design forcably interrupts/aborts the threads then it can't be
better than the situation above (IMO), and the above is just as
correct as waiting for the threads, which could bring bad cases
depending how long it takes to get between your violet flag checks,
expecially when you don't have to be waiting around (performance
wise).

NB
Peter Duniho - 06 Apr 2008 20:29 GMT
> On Apr 6, 11:20 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
> wrote:
[quoted text clipped - 3 lines]
> I think you miss read some place, I've never used the word data
> structures anywhere here,

You don't need to use the phrase "data structure" to be talking about a  
data structure.  The ReaderWriterLockSlim class is a data structure.

Rather than going through the rest of your post point by point though, I  
think the most productive thing is to focus on this:

> [...]
> I walk talking about this.  To be more specific, basically I said that
[quoted text clipped - 4 lines]
> violet flag (which, intuativaly, gets checked - and can immidatly exit
> the thread when it is checked and found violet).

First of all, I think the word you want is "volatile".  Secondly, what  
does that have to do with the paragraph I quoted in which you discussed  
the use of the thread pool?

That said, let's ignore the non-sequitur for the moment and focus on what  
you did write.  I note, by the way, that you have changed your suggestion  
so that your threads now exit when they note the synchronization object as  
being disposed, rather than simply continuing to process without the  
benefit of synchronization as you suggested earlier.  For what it's worth,  
that doesn't actually change the reality of the situation though.  You  
still need to wait for the threads to exit (or at a minimum, to signal  
back that they've acknowledged the "exit early" signal).

In particular...

Unless your Dispose() method is thread-safe (this is true for  
ReaderWriterLockSlim, but that class has no way to check whether it's  
actually disposed, so you must be talking about some other class), you  
cannot reliably check the disposed state as a way of knowing whether it's  
safe to use the synchronization object.  For some other class to be  
thread-safe, you need to introduce some thread synchronization.  
Otherwise, one thread could be just about to dispose the synchronization  
object, but not yet have set the "disposed" flag, while another thread is  
about to try to use the object that's about to be disposed (having already  
checked the flag).  If the latter thread now gets preempted and the first  
thread gets to run and dispose the object, the second thread is screwed  
when it eventually gets to run again.

So, either you introduce a new volatile flag to indicate that the threads  
need to exit and not dispose your synchronization object until the threads  
have exited (in which case that's exactly the "signal the thread to exit"  
design I said was one legitimate way to address the issue), or you have to  
add a new synchronization object to the design to protect the retrieval of  
the dispose state (in which case, now you have to wait for all the threads  
to exit before you can dispose _that_ synchronization object).

In other words, you have a paradox in your argument that always leads to  
creating a design that is exactly as I suggested it needs to be in the  
first place: you either need a signal to the threads to get them to stop  
processing, or you need to simply wait until they're completely done.  
Either way, you can't clean up until the threads are all done.

If you like, feel free to post a concise-but-complete implementation that  
does what you think is okay, using a disposable synchronization object  
that your threads make use of as you've described above.  I will be happy  
to point out in that concrete example the scenario in which your threads  
fail to produce correct behavior (whether because they simply don't  
produce synchronized output, or they actually crash trying to use a  
disposed object).

Pete
NvrBst - 06 Apr 2008 21:16 GMT
On Apr 6, 12:29 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> rather than simply continuing to process without the
> benefit of synchronization as you suggested earlier.

I don't remember ever saying that.  If you thought that I'm sorry,
but, as a said, if your checking the disposed flag before using a
disposable object, of course your gonna have an else statment to stop/
clean up if your object is disposed...

> The ReaderWriterLockSlim class is a data structure.

If thats the structure your talking about then the "If your thread
wants to use the structure" statment you said is invalid...  The
thread doesn't want to use that structure anymore if it's disposed,
else you wouldn't be disposing.

> Secondly, what
> does that have to do with the paragraph I quoted in which you discussed
> the use of the thread pool?

... The part about designing the solution to interrupt the thread.
Specifically if your thread pool is designed to have your worker
threads list themselves in a static variable, thus points to the
"using them like suggested isn't correct", and your statment about
having to interrupt the thread pool, there is no other way.  I was
pointing out the valid alternative to "design is flawed".

> So, either you introduce a new volatile flag to [...]

I never said replace the violate flag, its like batman and robin.  If
the violate flag is batman, then the dispose would be robin.  You'd
still need a way to tell the threads to stop without disposing your
object.

Your race condition situation is true for anyone trying to use the
disposed flag in a multithreaded situation.  You might as well be
saying that the dispose pattern as we know it is only made for STA
applications. IE Since, is most online examples of the dispose
pattern, the disposed flag gets set after you clean up the managed
resources.  What if you call Dispose on an object, then your other
thread checks the disposed flag and enters the if statment, then the
disposed method sets the dispose to false.  Application will crash.
Will it ever happen?  Most likly never, can it happen?  Yes.  It's how
multithreaded programers live.

I have to say, this conversation is getting a little pathedic...
Definally off topic...
NvrBst - 06 Apr 2008 21:45 GMT
I thought it'd be fun to make a "concrete" example :)  Please tell me
the incorrect sychronization, or crash.  Only requirment is that when
"Hello" gets displayed, "Goodbye" 100% has to be displayed.  If it
doesn't then my program failed.  Feel free to add Sleeps anywhere.  It
uses a disposable sychronization object (RWLS).

class Program {
   static void Main(string[] args) {
       Class1 myTest = new Class1();
       myTest.StartWork();
       myTest.Dispose();
       Thread.Sleep(1000);
   }
}

class Class1 {
   private ReaderWriterLockSlim myStringLock = new
ReaderWriterLockSlim();

   public void StartWork() {
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
   }

   public void test(Object nullState) {
       if(!disposed) myStringLock.EnterWriteLock(); else return;
       try {
           foreach(string A in new string[] { "hello", "goodbye" })
Console.WriteLine(A);
       } finally { if(!disposed) myStringLock.ExitWriteLock(); }
   }

   private bool disposed = false;
   public void Dispose() { Dispose(true); }
   protected virtual void Dispose(bool disposing) {
       if(!disposed) {
           disposed = true;
           if(disposing) myStringLock.Dispose();
       }
   }
}
Peter Duniho - 07 Apr 2008 01:15 GMT
> I thought it'd be fun to make a "concrete" example :)  Please tell me
> the incorrect sychronization, or crash.  Only requirment is that when
> "Hello" gets displayed, "Goodbye" 100% has to be displayed.  If it
> doesn't then my program failed.  Feel free to add Sleeps anywhere.  It
> uses a disposable sychronization object (RWLS).

Sure, no problem.  See code posted below.

The important change is that I added two events to ensure that the two  
threads were pre-empted in precisely the order that would cause a problem  
were the thread scheduler to happen to randomly schedule the threads in  
that order.  I also removed the second thread pool worker.  It's not  
necessary or relevant.

It's very important that you understand that there's nothing magic about  
the events I added.  They don't do anything except ensure broken behavior  
_every_ time.  The exact order they impose on the code is an order that  
the thread scheduler could at any time wind up causing to happen all by  
itself.  Without proper synchronization, there's no way to ensure that it  
doesn't.

Enjoy.  :)  I hope that having a concrete, broken example to look at helps  
illustrate better the risk in the design you've proposed.

Pete

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace TestBadSynch
{
    class Program
    {
        static void Main(string[] args)
        {
            Class1 myTest = new Class1();
            myTest.StartWork();
            myTest.Dispose();
            Thread.Sleep(1000);
        }
    }

    class Class1
    {
        private ReaderWriterLockSlim myStringLock = new  
ReaderWriterLockSlim();
        private AutoResetEvent _are1 = new AutoResetEvent(false);
        private AutoResetEvent _are2 = new AutoResetEvent(false);

        public void StartWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(test));
            // ThreadPool.QueueUserWorkItem(new WaitCallback(test));
        }

        public void test(Object nullState)
        {
            if (!disposed)
            {
                _are2.Set();
                _are1.WaitOne();
                myStringLock.EnterWriteLock();
            }
            else
            {
                return;
            }
            try
            {
                foreach (string A in new string[] { "hello", "goodbye" })
                    Console.WriteLine(A);
            }
            finally
            {
                if (!disposed)
                {
                    myStringLock.ExitWriteLock();
                }
            }
        }

        private bool disposed = false;
        public void Dispose() { Dispose(true); }
        protected virtual void Dispose(bool disposing)
        {
            _are2.WaitOne();
            if (!disposed)
            {
                disposed = true;
                if (disposing) myStringLock.Dispose();
                _are1.Set();
            }
        }
    }
}
Peter Duniho - 07 Apr 2008 00:35 GMT
> On Apr 6, 12:29 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
> wrote:
>> rather than simply continuing to process without the
>> benefit of synchronization as you suggested earlier.
>
> I don't remember ever saying that.

You wrote:

    waiting around for the threads to finish isn't always a
    perferred solution; maybe the locks were there to
    syncronize actions (IE in the case of a chat program,
    the thread could lock the send/recive method on a line
    basis, so if you stop locking the worst that could happen
    would be something like Msg1: "hello jim."  Msg2: "test",
    resulting in "hetleslo jim .\nt".  If your cleaning up,
    your probably not caring what else the threads going to
    do as long as it doesn't crash, etc

From the statement "waiting around for the threads to finish isn't always  
a perferred [sic] solution", we know that you intend for the threads to  
continue processing.  The statement "if you stop locking the worst that  
could happen would be..." further implies that it's not that the threads  
will stop executing when they notice the lock's not around, but rather  
that they will simply continue working without synchronization.

> If you thought that I'm sorry,

I only thought you said that because you did.  I'm happy if you want to  
retract the previous example, but you did post that scenario as an example.

> but, as a said, if your checking the disposed flag before using a
> disposable object, of course your gonna have an else statment to stop/
> clean up if your object is disposed...

You can't check the disposed flag without synchronizing access to it.

>> The ReaderWriterLockSlim class is a data structure.
>
> If thats the structure your talking about then the "If your thread
> wants to use the structure" statment you said is invalid...  The
> thread doesn't want to use that structure anymore if it's disposed,
> else you wouldn't be disposing.

You can write "the thread doesn't want to use that structure anymore" all  
you want.  Until you've actually _shown_ why it's valid for the thread to  
"not want that structure anymore", it's meaningless.  If the thread needed  
the structure before, no other thread can safely dispose the structure  
until the thread has in some way signaled that it no longer needs it.  You  
can't just dispose it and assume that the other thread can detect that  
before it next tries to use it.

>> Secondly, what
>> does that have to do with the paragraph I quoted in which you discussed
[quoted text clipped - 6 lines]
> having to interrupt the thread pool, there is no other way.  I was
> pointing out the valid alternative to "design is flawed".

Again: I never once suggested that you _should_ be aborting thread pool  
threads.  Please stop using that red herring.  It has nothing to do with  
this.

>> So, either you introduce a new volatile flag to [...]
>
[quoted text clipped - 7 lines]
> saying that the dispose pattern as we know it is only made for STA
> applications.

Well, many disposable objects are specifically documented as not being  
thread-safe.  However, Microsoft does also specifically _recommend_ that  
if you implement Dispose() that it be valid to call Dispose() multiple  
times safely.

But most disposable classes don't provide any mechanism for checking to  
see whether they are disposed.  Only a class that does, _and_ which is  
documented as being thread-safe, would permit the sort of design you're  
talking about.  I'm not aware of any such class in .NET.  Certainly the  
classes we've discussed in this thread don't fit that description.

> IE Since, is most online examples of the dispose
> pattern, the disposed flag gets set after you clean up the managed
> resources.

None of those examples are intended to show a thread-safe implementation  
of Dispose().  They simply use the flag as an optimization.

> What if you call Dispose on an object, then your other
> thread checks the disposed flag and enters the if statment, then the
> disposed method sets the dispose to false.  Application will crash.
> Will it ever happen?  Most likly never, can it happen?  Yes.  It's how
> multithreaded programers live.

NO!  That's not how competent programmers who write multi-threaded code  
live.  "Most likely never happen" is NEVER an appropriate design  
philosophy.

For classes that follow Microsoft's recommendation that the Dispose()  
method be safe to call multiple times from multiple threads, you can get  
away with doing so.  But only for those classes, and only because the  
Dispose() method has already been designed to support that.  There's no  
question of whether that will ever break for those questions; it won't,  
because the class has been designed to support that.

But beyond that, being able to call Dispose() multiple times isn't the  
same as whether it's safe to dispose an object in one thread while another  
thread might try to use it.  The two are related issues, but not the same  
at all.

> I have to say, this conversation is getting a little pathedic...
> Definally off topic...

It's no more off-topic than any other programming design thread, of which  
we have many here in this newsgroup.

If anything, I find that this discussion is of great importance, because  
if anyone follows your advice, they are heading down the road to serious  
trouble.  I want to make sure that it's as clear as possible that you  
cannot design multi-threaded code in the way you suggest and still have  
correct code.  Even better would be if I'm able to convince you, but I  
recognize that not all people are prepared to admit that they have made a  
mistake.

Pete
NvrBst - 07 Apr 2008 01:54 GMT
> I only thought you said that because you did.  I'm happy if you want to
> retract the previous example, but you did post that scenario as an example.

That was an example to illustrate what would happen if you got past
the (disposable) lock before it disposed, but not result in a crash
and be a valid "not care about the results anymore"; user wise.  If it
was before the lock when it disposed, then it wouldn't result in any
output because it'd see the object is disposed and just skip to the
end.  It's like using it to generlize the topic to chat programs only
- "whats all this talk about thread pools, I thought we were talking
about chat programs"

> Again: I never once suggested that you _should_ be aborting thread pool

Amusing, red herring?  You gave the example.  Said its the only valid
way if you were in that situation to safly clean up (which I
dissagreeded with).  You can keep following the straw man argument
above if you like, but don't tell me to not try to refret the "only"
way to safly dispose the thread pool without waiting argument you
gave, and then call it a red herring.

> However, Microsoft does also specifically _recommend_ that
> if you implement Dispose() that it be valid to call Dispose() multiple
> times safely.

I didn't design the dispose pattern.  It comes with a "disposed" flag
that they expect you to use.  What if 2 objects try to dispose at the
same time, and both objects try setting the "disposed" flag to false
at the same time?  Is the design patter flawed?  Not really, the
situation doesn't really occur ever, but it probably can since who
knows when the GC will call it.  I wouldn't spend too much time trying
to fix this situation even though it can potentially exsist.

> "Most likely never happen" is NEVER an appropriate design
> philosophy.

I'm not too sure about this statment...  It's not that perfect of a
world.

> It's no more off-topic than any other programming design thread

:) It's definally off-topic, but I retract my previous statment.  It's
not pathedic, I don't know why I said that.  I don't see myself as the
kind of person who has a problem admiting I made a mistake, I just
don't agree with your view.

In my opinion, it's possible to (as reliably as other programs), clean
up an object and not be forced to wait for the threads inside it to
finish, or force threads to stop with an abort.  Mainly in the case
where you don't care about the result of the threads anymore.  Another
example could be that you send 100 threads off to get an answer, you
got the answer when the 3rd thread returned.  You can do clean up and
ignore the other threads as long as you have dispose checks (or try
catch statments (or both)), around the objects you clean up.

Now don't get me wrong.  A disposable sychronization lock did seem
very strange to me (point of the topic), and obviously makes using
this type of lock in a situation where you want to do fast clean up
makes it harder (if statmtnet, or try catch statments, everytime you
try and aquire a lock).  But this isn't a bad design, the benifites
can be good.

IE in the previous example changing all the "if(!disposed)
myStringLock.EnterWriteLock(); else return;" to "try
{ myStringLock.EnterWriteLock(); } catch { return; }" would fix any
possible crashes, and be a concret example with no possible chance of
crashing, yet have everything synched.

:) NB
NvrBst - 07 Apr 2008 02:00 GMT
hehe, We got a synch problem going on!  :)  Aye I seen the case where

1. if(!disposed)
2. disposed = true;
2. RWLS.dispose();
1. RWLS.Aquire Lock

How often?  0.0001% maybe.  As listed in previous example try this one

class Program {
   static void Main(string[] args) {
       Class1 myTest = new Class1();
       myTest.StartWork();
       myTest.Dispose();
       Thread.Sleep(1000);
   }

}

class Class1 {
   private ReaderWriterLockSlim myStringLock = new
ReaderWriterLockSlim();

   public void StartWork() {
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
       ThreadPool.QueueUserWorkItem(new WaitCallback(test));
   }

   public void test(Object nullState) {
       try {myStringLock.EnterWriteLock();} catch(Exception)
{ return; }
       foreach(string A in new string[] { "hello", "goodbye" })
Console.WriteLine(A);
       try {myStringLock.ExitWriteLock(); } catch(Exception)
{ return; }
   }

   private bool disposed = false;
   public void Dispose() { Dispose(true); }
   protected virtual void Dispose(bool disposing) {
       if(!disposed) {
           disposed = true;
           if(disposing) myStringLock.Dispose();
       }
   }

I added 2 more queue work items because I wanted too :P  I don't think
this example can crash.  Putting both the !disposed would make
~99.999999% of the users never trigger the catch statment, makes one
almost not want to put it there ;)

NB
Peter Duniho - 07 Apr 2008 03:38 GMT
> hehe, We got a synch problem going on!  :)  Aye I seen the case where
>
[quoted text clipped - 4 lines]
>
> How often?  0.0001% maybe.  As listed in previous example try this one

Your new example fails to crash solely by virtue of catching the  
exception.  That doesn't mean it's thread-safe; it just means you wrapped  
bad code in an exception handler and decided to ignore the design problem.

I can write any program so that it doesn't crash, using the same  
technique.  If using that technique were a valid proof of correct design,  
then no program could be considered incorrect.

Pete
Peter Duniho - 07 Apr 2008 03:53 GMT
> [...]
>> However, Microsoft does also specifically _recommend_ that
[quoted text clipped - 3 lines]
> I didn't design the dispose pattern.  It comes with a "disposed" flag
> that they expect you to use.

Not for the purpose of making the call thread-safe with other operations  
on the class, they don't.

> What if 2 objects try to dispose at the
> same time, and both objects try setting the "disposed" flag to false
> at the same time?

If it's safe to do whatever work inside the method from two different  
threads at the same time, then there's no problem at all.  All that  
happens is some redundant work.  There's no risk at all in having two  
different threads setting the same flag to "true" at the same time.  Or  
even "false" as you wrote, if you really think that setting the "disposed"  
flag to "false" in the "Dispose()" method is the right way to do it.

> Is the design patter flawed?

I never said it was flawed.  But it's not thread-safe with other  
operations on the class.

> Not really, the
> situation doesn't really occur ever, but it probably can since who
> knows when the GC will call it.  I wouldn't spend too much time trying
> to fix this situation even though it can potentially exsist.

I hope no one is paying you for your coding efforts then.  It's one thing  
to be ignorant of a design problem and overlook it.  It's quite another to  
know it exists and just ignore it.  The latter is professionally  
irresponsible.

> [...]
> In my opinion, it's possible to (as reliably as other programs), clean
> up an object and not be forced to wait for the threads inside it to
> finish, or force threads to stop with an abort.

If it were a matter of opinion, then your opinion might matter.  But it's  
not a matter of opinion.  You can't write reliable code in that way.

> Mainly in the case
> where you don't care about the result of the threads anymore.

Whether you care about the result of the threads anymore is irrelevant.  
Cleaning up something the threads need for proper operation can result in  
data corruption or an immediate crash.  Neither is appropriate in a  
program that is to be considered reliable.

The only reason you can ignore this issue is if you are happy with the  
program being unreliable.  Personally, I don't write programs that I know  
to be unreliable.

> Another
> example could be that you send 100 threads off to get an answer, you
> got the answer when the 3rd thread returned.  You can do clean up and
> ignore the other threads as long as you have dispose checks (or try
> catch statments (or both)), around the objects you clean up.

Not and have a reliable program, you can't.  And it's so easy to write the  
code reliably, that it's just silly to not do so.

You have spent more time arguing about the issue than it should take you  
to implement a "signal, wait, clean up" design in half a dozen programs.

> [...]
> IE in the previous example changing all the "if(!disposed)
> myStringLock.EnterWriteLock(); else return;" to "try
> { myStringLock.EnterWriteLock(); } catch { return; }" would fix any
> possible crashes, and be a concret example with no possible chance of
> crashing, yet have everything synched.

As I noted in my other post, wrapping the call in a try/catch doesn't  
address the underlying design issue, nor does it any way validate the  
design choice.  That said, I find it amusing that you don't like the idea  
of aborting a thread (as well you shouldn't), but you're perfectly happy  
to have it throw an exception that you catch and use to terminate the  
thread.  There's very little difference between the two approaches.

Pete
NvrBst - 07 Apr 2008 19:01 GMT
On Apr 6, 7:53 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> As I noted in my other post, wrapping the call in a try/catch doesn't  
> address the underlying design issue, nor does it any way validate the  
> design choice.  That said, I find it amusing that you don't like the idea  
> of aborting a thread (as well you shouldn't), but you're perfectly happy  
> to have it throw an exception that you catch and use to terminate the  
> thread.  There's very little difference between the two approaches.

Amusing, are there any other requirments?  Am I allowed to use if
statments?  :)  Its a joke :P.  You say "it doesn't crash", but thats
not just the case, you should be saying "it doesn't crash, and
maintains the strick sychronization requirments", and all other
requirments/functions of the program for that matter, with no
possibility of ill effects.  It does exactly what the client paid for,
and doesn't have any dead weights running around.

I don't know why you wouldn't call it a valid design, it uses a
boolean to check the object before using it, and in the rare case of
object being disposed between the ")", then it does whatever cleanup
the thread might want to do, and exit, in a valid way to maintain
sychronization.

From what your saying here it's like you've never opened a file in
your life as a programmer (which is the same design pattern as I'm
using).  You check the file to see if its valid, and then open it.
Can something grab the file between the check and opening?  Definally,
does it make it a bad design?  Definally not.

You show me a method of opening a file without a try/catch statment
that doesn't crash, and I'll show you how to check for use of a
disposable object that can be disposed anytime.

Rest of your statments are just plaintly close minded.  Telling people
there is no way to do something (correctly), is extremly ignorant, "I
hope no one is paying you for your coding efforts then" with that kind
of mindset, a real programmer see's a problem, and accoplish's it.  He
doesn't whine about a try/catch statment, he whines about the
performance/robustness/correctness (problem wise) of a solution.

NB

PS: I'm not saying this is the only way to do things.  I've made
programes with all three techniques mentioned here and will agree that
signling threads to finish and waiting for them to finish to dispose
is one way to do it.  It doesn't make it the best way for all cases in
the world... unlike your mindset, the world is not that small of a
place.
Peter Duniho - 08 Apr 2008 02:53 GMT
> [...]
> Amusing, are there any other requirments?  Am I allowed to use if
[quoted text clipped - 4 lines]
> possibility of ill effects.  It does exactly what the client paid for,
> and doesn't have any dead weights running around.

Exceptions are costly, and so it's certainly not true that your design  
"doesn't have any dead weights running around".  As far as the question of  
"no possibility of ill effects", in your specific example that's true, but  
you can't extrapolate that to any arbitary implementation that uses the  
same technique.

> I don't know why you wouldn't call it a valid design, it uses a
> boolean to check the object before using it, and in the rare case of
> object being disposed between the ")", then it does whatever cleanup
> the thread might want to do, and exit, in a valid way to maintain
> sychronization.

Why do you bother checking the boolean at all?  It's not protecting you in  
any way.

It's a bad design because it has code that tries to do something, but  
because you haven't designed the code to be reliable, you wind up having  
to add a bandage to catch the fact that the code isn't reliable.

This code performs its duty perfectly:

    try
    {
        string[] rgstr = { "one", "two", "three" };

        for (int i = 0; i <= rgstr.Length; i++)
        {
            Console.WriteLine(rgstr[i]);
        }
    }
    catch { }

But that doesn't mean that it's been designed correctly.  And in fact, it  
hasn't been designed correctly.  The above is just like your proposed  
"catch disposed exception" solution, which is just as incorrect a design.

> From what your saying here it's like you've never opened a file in
> your life as a programmer (which is the same design pattern as I'm
> using).

Opening a file and catching a possible failure is nothing like the design  
pattern you're using.  Just because both examples use try/catch, that does  
not make them the same design pattern.  Still, the "open file" pattern you  
describe is just as flawed as the "catch disposed exception" pattern  
you're promoting.  Specifically...

> You check the file to see if its valid, and then open it.
> Can something grab the file between the check and opening?  Definally,
> does it make it a bad design?  Definally not.

Writing code that checks a file to see if it's valid and then tries to  
open it is stupid.  Because of the exact issue you're describing, there's  
absolutely no point in doing any verification of the file before opening  
it.  You should just try to open it.  That's your verification right there.

> You show me a method of opening a file without a try/catch statment
> that doesn't crash, and I'll show you how to check for use of a
> disposable object that can be disposed anytime.

The two situations are entirely different.  It's trivial to write code  
that doesn't need to catch an "object disposed" exception.  But as you  
pointed out, because the file system is not under the process's control,  
there's no way to ensure that opening a file won't throw an exception.

> Rest of your statments are just plaintly close minded.  Telling people
> there is no way to do something (correctly), is extremly ignorant,

You're welcome to your opinion.  But I'm welcome to mine too, and I  
certainly am of the opinion that it's extremely ignorant to write code  
that throws exceptions when you could just as easily write it correctly  
and without the code failing intentionally.

> "I hope no one is paying you for your coding efforts then" with that kind
> of mindset, a real programmer see's a problem, and accoplish's it.

No.  A real programmer doesn't just make his program work.  He designs it  
with care and attention to detail, making it maintainable, robust, and  
efficient.  He does not just add duct tape until the thing works.  He  
strives to make the solution as elegant as it is useful.

Pete
NvrBst - 08 Apr 2008 03:46 GMT
> Exceptions are costly
> Why do you bother checking the boolean at all?

Amusing.   You answered your own quesiton, I'm just unsure if you
realized it yourself?  Exceptions are costly, you want to minimize
them.

> This code performs its duty perfectly:

Other than the fact that your not catching any specific excpetion I
can see.  If you wanted a global exception handler there are better
ways.

> But that doesn't mean that it's been designed correctly.

It does...  Putting a try/catch statment around potentially hazardous
code is exactly what it was designed to do.  A good programmer can see
a hazard (even 0.001% case), and fix it with the try statment -
acuratly so that program continues normally as intended.

> You should just try to open it.  That's your verification right there.

If anyone is readining (which probably not anymore), I'd highly
suggest not listening to this part here.  Minimize your excpetions
because they are costly.  For example.  If pete wants to open a file
he's not 100% sure exsists, he'll "try( File.Open(file) }..." while
what you really should do is a "if(File.Exsists(file)) open" and wrap
that in a try statment if needed for a chance it doesn't exsits after
you just checked it.  Unless your very sure the file exsists, you
should do the Exsists check to maxmize performance.

End result, minimize your exceptions people.  It's simple math, heres
the equation:

Performance Overhead (ms) = AverageChanceOfExcpetion% * ExceptionCost
+ AverageChanceOfNoneException% * CheckCosts
 AKA CheckCosts = ~0.1ms.  ExceptionCosts = 1000x that.  What you
want to minimize?

> He does not just add duct tape until the thing works.

End result, the program, binary wise, would be able to stand up to any
other implementation in any kind of benchmarking, performance,
reliablity tests, not only that, it may even surpass the other
designs.  What would the judges(clients) say is better?  They don't
care if if one uses a string and the other uses a char[], they care
what gets the job done the fastest.

NB
Peter Duniho - 08 Apr 2008 04:00 GMT
> [...]
>> You should just try to open it.  That's your verification right there.
>
> If anyone is readining (which probably not anymore), I'd highly
> suggest not listening to this part here.

I would be surprised if there is anyone still following this thread who  
agrees with the design philosophy you're promoting, including your  
suggestion that checking for validity of a file operation before actually  
attempting the operation is a worthwhile thing to do.

> [...]
> End result, the program, binary wise, would be able to stand up to any
[quoted text clipped - 3 lines]
> care if if one uses a string and the other uses a char[], they care
> what gets the job done the fastest.

Performance is one the last criterias that should be of concern in program  
design.  Maintainability, simplicity, and reliability are much more  
important.  And for certain, writing bad code just because you think it  
will perform better is just plain wrong.

Pete
NvrBst - 08 Apr 2008 06:17 GMT
On Apr 7, 8:00 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > [...]
> >> You should just try to open it.  That's your verification right there.
[quoted text clipped - 21 lines]
>
> Pete

You remind me of steve jobs.  The crazy crazy personality type who
doesn't care about money, he just wants to make sure everyone does
things his way.  In comparason I'd be like Bill Gates, still crazy,
but money crazy.

Incase the analagy is lost on you, Money = Perfomrnace, and Design is
you freaking out about people doing things your way or they are
wrong.  It's also like the Nazi's "Theres no place in this world for a
disposable thread sychronization object, GAS THEM".

At least your not saying it wouldn't run worst :P

NB
Peter Duniho - 08 Apr 2008 07:23 GMT
> You remind me of steve jobs.  The crazy crazy personality type who
> doesn't care about money, he just wants to make sure everyone does
> things his way.

Neither of us know Jobs personally and thus are not qualified to make any  
sort of determination regarding his personality.

That said, I doubt it's true that he doesn't care about money.

> In comparason I'd be like Bill Gates, still crazy,
> but money crazy.

I have somewhat better insight regarding Gates, though I still wouldn't  
say I know him personally.  I would definitely not describe him as "money  
crazy".

But regardless...

> Incase the analagy is lost on you, Money = Perfomrnace, and Design is
> you freaking out about people doing things your way or they are
> wrong.

You have some learning to do with respect to the economics software  
development.  It is not true that "Money = Performance".  In fact, your  
proposed design has very minimal impact on performance, certainly not  
enough for any client to notice, and yet it has a significant negative  
impact on development cost.

Assuming the client will pay a given amount of money for a solution, the  
less time you spend on making that solution, the more profit you have.

Even a person who is "money crazy" would be a fool to choose the design  
you've proposed.  That design is only going to cost them money.  There's  
no way it's going to improve their bottom line.

> It's also like the Nazi's "Theres no place in this world for a
> disposable thread sychronization object, GAS THEM".

Really?  You really think a Nazi analogy is appropriate here?  Are you  
intentionally invoking Godwin's Law?

Sheesh.  And you can't even be bothered to do it in a relevant way, seeing  
as how nothing I've written has anything to do with whether there's a  
"place in this world for a disposable thread synchronization object".

Pete
NvrBst - 08 Apr 2008 19:11 GMT
I got a relation to Mac and Nazi in one post, your looking evil now,
wuahah.

> It is not true that "Money = Performance".

In a metaphore or analogy, it can mean anything I want as long as the
persons smart enough to pass those classic IQ tests (_ is to _ as _ is
to _).  Else I have to spoon feed it to them... which isn't as fun.

People think in different ways than others.  Forcing someone to write
code in a certain way will only prologe the development process.  If a
person wants to dispose straight away and let threads do their thing,
then thats just the way he thinks.  For small classes it might even be
the best way IMO.  I'd like to see your proof on this method taking
longer/cost more to develop, but I think we both know there isn't any
(expecially if the developer already has that solution in his mind...
you want to force a different thought process into this guys head with
no "good" reasion as I can see).  You agree performance wise it isn't
worst, you seem to think it'll be harder to maintain which isn't true
either - as long as its commented right it'll be just as easy as any
other implementation.  You seem to think it'll take longer to develop,
for some maybe, the reverse is true for others.

Now if you were giving valid reasion's, even I'd convert and say "oww
definally want to do it that way, I see why now", but the "nope, the
design is flawed because it's not the way I do it.  You way works just
as good, but costs more to develop." is a very hard argument stance to
succeed in.

NB
Peter Duniho - 08 Apr 2008 22:23 GMT
> I got a relation to Mac and Nazi in one post, your looking evil now,
> wuahah.
>
>> It is not true that "Money = Performance".
>
> In a metaphore or analogy,

I know.  But it's not a correct one.  That's my point.  Had you bothered  
to read the rest of what I wrote, you'd understand what I meant.

> [...]
> People think in different ways than others.  Forcing someone to write
> code in a certain way will only prologe the development process.

It is objectively true that the design I've suggested is simpler to  
implement and simpler to maintain.  For an inexperienced programmer it may  
well be that it might take them a little more time to learn the concept,  
but in the long run even they will spend less time on it.

> If a
> person wants to dispose straight away and let threads do their thing,
> then thats just the way he thinks.

Computers only think one way.  It is the job of the programmer to learn to  
think the way the computer thinks, so that he is not fighting the computer  
as he writes the code.

Beyond that, while it is not possible to write correct code that disposes  
objects threads might use before those threads exit, it's certainly  
possible to write "fire and forget" code that allows the clean-up to  
happen while the rest of the application continues on doing whatever it  
was doing.  This should be sufficiently close to the paradigm of "dispose  
straight away and let threads do their thing" that even the person for  
whom "that's just the way he thinks" could easily comprehend and use such  
a design.

> For small classes it might even be
> the best way IMO.  I'd like to see your proof on this method taking
> longer/cost more to develop, but I think we both know there isn't any

I guess that depends on what you consider proof.  However, your proposed  
design can be implemented in a couple of ways: a single try/catch at the  
very top of the thread's call chain, or a try/catch around each and every  
possible use of a disposable object.

In the former case, the initial implementation is quick, but then you  
create a situation in which you can't tell whether you're catching an  
expected exception or one that represents some other bug.  That's a  
situation that is demonstrably a huge maintenance risk.

In the latter case, you can ensure that you're not catching exceptions  
that shouldn't be hidden.  But at the very least you've now committed to a  
huge amount of work to wrap every single one of your uses of a disposable  
object in a try/catch handler.  In addition, you now introduce the risk of  
missing one of those uses.

These are clear code maintenance problems, ones that will necessarily and  
unavoidable result in higher maintenance costs for the code.

On the other hand, the design I've proposed carries no hidden performance  
costs, is 100% predictable, and as a result of that can be easily shown to  
correctly deal with tearing down worker threads.

> (expecially if the developer already has that solution in his mind...
> you want to force a different thought process into this guys head with
> no "good" reasion as I can see).  You agree performance wise it isn't
> worst, you seem to think it'll be harder to maintain which isn't true
> either

I don't "seem to think".  I know.

>  - as long as its commented right it'll be just as easy as any
> other implementation.

No, it won't.  Because of the issues I describe above, the exception-based  
design inherently carries higher maintenance costs.

> You seem to think it'll take longer to develop,
> for some maybe, the reverse is true for others.

I never said it would necessarily take longer to develop.  In fact, if you  
just wrap the whole thread in a single try/catch, the initial development  
cost is almost certainly lower with your proposed design.  But that's not  
the only cost that is of concern, and in fact it's the least important  
cost to consider.  The total cost of maintaining the code over the  
lifetime of the code is what you need to consider.

> Now if you were giving valid reasion's, even I'd convert and say "oww
> definally want to do it that way, I see why now", but the "nope, the
> design is flawed because it's not the way I do it.

I have provided numerous reasons, all of them valid.  It's unfortunate  
that you are so committed to your previous position that you cannot see  
the validity of what I've written.  But it doesn't change the facts.

By the way, much of what I've said is based on my own personal experience  
over the years.  However, there's a very good book by Steve McConnell,  
called "Code Complete", that does a good job of covering these kinds of  
issues.  I don't recall off the top of my head whether it addresses this  
specific kind of design issue, but a person who reads the book and takes  
to heart the general coding philosophy that McConnell is promoting will  
naturally understand what I'm talking about here.

> You way works just
> as good, but costs more to develop." is a very hard argument stance to
> succeed in.

To the contrary.  I've made very specific statements about where and why  
the design I propose is simpler and lower-cost to maintain over the long  
run than the design you propose.  You have ignored those statements  
wholesale, rejecting them for reasons known only to you.  But that doesn't  
mean they are invalid.

Pete
NvrBst - 08 Apr 2008 22:50 GMT
> In the former case, the initial implementation is quick, but then you
> create a situation in which you can't tell whether you're catching an
> expected exception or one that represents some other bug.

Your catching a very specific exception "Object null exception", other
exceptions wont be caught.

> But at the very least you've now committed to a
> huge amount of work to wrap every single one of your uses of a disposable
> object in a try/catch handler.

It's a lock object... you grab it once and release it shortly after,
probably 75%+ of the time.

Furthermore, if you implement it this way, then users have a lot
easier time using the object.  They simply call ".Dispose()" when they
are done with it (little more effort in the design I agree to ensure
proper clean up in all situations).  The other solutions put more
effort in different parts of the project (IE clean up methods, thread
stoping.  Putting logic like this in the dispose would world very
well), which basically pushes the responsablity onto the user of the
class because you don't want to harder maintance.

In my eyes, maintainence is as simple, it intuativly becomes 'thread
safe', and easier for others to use.  Weighed against your "harder to
maintain even with good commenting".  It's not a replacment, they both
have different pros and cons.  Surly you should be able to see that...

NB
Peter Duniho - 08 Apr 2008 23:06 GMT
>> In the former case, the initial implementation is quick, but then you
>> create a situation in which you can't tell whether you're catching an
>> expected exception or one that represents some other bug.
>
> Your catching a very specific exception "Object null exception", other
> exceptions wont be caught.

First of all, it's the ObjectDisposedException.  Second, so what?  You are  
making the assumption that you will never write any code that accidently  
uses an object that's already disposed.  That's a rather broad assumption,  
one that will easily lead to higher maintenance costs if and when it turns  
out to be false.

>> But at the very least you've now committed to a
>> huge amount of work to wrap every single one of your uses of a  
[quoted text clipped - 3 lines]
> It's a lock object... you grab it once and release it shortly after,
> probably 75%+ of the time.

First of all, it's not just a lock object.  It's any object that you want  
to clean up.  Or are you saying that you have this preference to dispose  
an object that the threads are using only when it's a synchronization  
object, and that you will wait to dispose anything else the threads are  
using until they are done?

Unless you're saying that, then the text you quoted above applies to  
_every_ use of _every_ disposable object.

Secondly, there's nothing about your proposed design philosophy that  
stated you'd apply it only in very simple scenarios.  Synchronization  
objects are often used in multiple places, and there's really no  
theoretical limit to the number of places they could be used.  It depends  
only on the overall complexity of the code.

With the design I've proposed, no matter how complex the code in the  
thread gets, you still have a very simple strategy for exiting the  
thread.  With your proposal, the exit strategy for the thread increases in  
complexity as the complexity of the rest of the thread code does as well.  
Again, higher maintenance costs.

> Furthermore, if you implement it this way, then users have a lot
> easier time using the object.  They simply call ".Dispose()" when they
> are done with it (little more effort in the design I agree to ensure
> proper clean up in all situations).

There's absolutely no reason at all that, if that's of a concern to you,  
the object cannot deal with the "fire and forget" disposal using the  
design I've proposed.  Nothing about the design forces the disposal to be  
pushed onto the client of the class.

> The other solutions put more
> effort in different parts of the project (IE clean up methods, thread
> stoping.  Putting logic like this in the dispose would world very
> well), which basically pushes the responsablity onto the user of the
> class because you don't want to harder maintance.

Wrong.  See above.

> In my eyes, maintainence is as simple, it intuativly becomes 'thread
> safe', and easier for others to use.

First, as I point out above, ease of use need not be sacrificed.  But  
beyond that, ease of use is merely one part of maintainability.  Your  
proposed design is inherently more complicated and requires more code to  
implement.  These drastically increase maintenance costs.

> Weighed against your "harder to
> maintain even with good commenting".  It's not a replacment, they both
> have different pros and cons.  Surly you should be able to see that...

There's nothing to see.  Your proposal is inherently flawed and is not  
necessary in order to achieve any of your stated goals.  It's a lose-lose  
situation.

Pete
NvrBst - 08 Apr 2008 23:45 GMT
> That's a rather broad assumption,
> one that will easily lead to higher maintenance costs if and when it turns
> out to be false.

Not really, the try statment is designed to deal with that exact
exception.  As a result it'll clean up as intended even if it wasn't
the dispose method that made it null.

> Or are you saying that you have this preference to dispose
> an object that the threads are using only when it's a synchronization
> object,

I was still talking about the example provided.  It only has the
sychronization object.  Yes all "fast clean" dispose objects need to
be checked before use, but in practice this usally doesn't result in
many objects (~0-1).  Can I make a class that uses 100 disposable
objects?  Yes.  Can I use a bazuka to kill an ant?  Yes.

> Secondly, there's nothing about your proposed design philosophy that
> stated you'd apply it only in very simple scenarios.

It doesn't have to.  It depends entirly on the solution.  If the
amount of sychronization is simple though this pattern shines most.
Sychronization could be simple even in huge objects as well.

> Nothing about the design forces the disposal to be
> pushed onto the client of the class.

If your doing automatic clean up (IE in the dispose method), its not
going to work out very well, unless your simply killing the threads.
Anyway you do it, it'll either put more effort into your design
(effort that isn't needed in the other design since this case doesn't
apply / or already implemented), or your pushing it onto the client of
the class to make sure the object can be disposed before they dispose.

> Your
> proposed design is inherently more complicated and requires more code to
> implement.

A couple try/catch statment with some simple clean up in the catch
portion, vs whatever methods your creating (or automatic cleanup
logic).  They probably equal out, the only difference is one pushes it
into the code the other localizes it.

NB
Peter Duniho - 09 Apr 2008 01:32 GMT
>> That's a rather broad assumption,
>> one that will easily lead to higher maintenance costs if and when it  
[quoted text clipped - 4 lines]
> exception.  As a result it'll clean up as intended even if it wasn't
> the dispose method that made it null.

You don't seem to be paying attention to what I wrote.  The point is that  
you may accidently use an object that was disposed before the program was  
done with the thread.  The thread won't "clean up as intended".  It'll  
clean up before intended.

>> Or are you saying that you have this preference to dispose
>> an object that the threads are using only when it's a synchronization
>> object,
>
> I was still talking about the example provided.

So you're not talking about a general design pattern at all then.  I'll  
grant: with the very specific example you provided (that is, the demo code  
you posted) it really doesn't matter _what_ the implementation is.  The  
code's too short for it to make a difference.

I'm talking about real code.  You know, the kind that does actual work.

> It only has the
> sychronization object.  Yes all "fast clean" dispose objects need to
> be checked before use, but in practice this usally doesn't result in
> many objects (~0-1).  Can I make a class that uses 100 disposable
> objects?  Yes.  Can I use a bazuka to kill an ant?  Yes.

Practically any interesting code is going to use disposable objects, and  
in the general case it could easily be a large number of disposable  
objects.  With your proposal, assuming you're not limiting it just to the  
degenerate case you posted, your suggestion requires a try/catch around  
literally every use of every disposable object (assuming you want to avoid  
the first problem I described, in which you catch and suppress unintended  
uses of disposed objects).

>> Secondly, there's nothing about your proposed design philosophy that
>> stated you'd apply it only in very simple scenarios.
>
> It doesn't have to.

It does if you want to maintain it as a workable design philosophy (and  
even then, it's still higher maintenance than the correct way to do it).

> It depends entirly on the solution.  If the
> amount of sychronization is simple though this pattern shines most.

"This pattern" doesn't "shine" at all.  It's bad even in the simple  
scenario where you can at least look at all the code and not worry about  
it breaking.  And in a real-world scenario, it's a massive maintenance  
headache.

> Sychronization could be simple even in huge objects as well.

We're not talking about synchronization.  We're talking about object  
disposal.

>> Nothing about the design forces the disposal to be
>> pushed onto the client of the class.
>
> If your doing automatic clean up (IE in the dispose method), its not
> going to work out very well, unless your simply killing the threads.

Again, you don't seem to be paying attention.  My proposed design lends  
itself very well to "automatic clean up".  Personally, I feel it's better  
for the threads to just be signaled to exit, so they can quit taking up  
valuable processing resources.  But if you really insist on letting them  
just run, it's trivial to have an independent thread wait for them to  
finish and then dispose things properly at that point.  For that matter,  
you can easily design a "last one out of the room, turn off the lights"  
implementation (see below).

There is no need to dispose things right away, even if you want to keep  
the design simple.

> Anyway you do it, it'll either put more effort into your design
> (effort that isn't needed in the other design since this case doesn't
> apply / or already implemented), or your pushing it onto the client of
> the class to make sure the object can be disposed before they dispose.

Neither is true.

>> Your
>> proposed design is inherently more complicated and requires more code to
[quoted text clipped - 3 lines]
> portion, vs whatever methods your creating (or automatic cleanup
> logic).

The automatic cleanup logic is minimal.  No new methods are needed at all,  
and the logic can be as simple as decrementing a counter and cleaning up  
if it hits 0.

For example, here's a version of your original example that delays  
disposal until all the threads are done, without imposing any new  
requirements on the client:

    class Class1
    {
        private ReaderWriterLockSlim myStringLock = new  
ReaderWriterLockSlim();
        private int _cthread;
        private volatile bool _fDispose;

        public void StartWork()
        {
            _cthread = 2;
            ThreadPool.QueueUserWorkItem(new WaitCallback(test));
            ThreadPool.QueueUserWorkItem(new WaitCallback(test));
        }

        public void test(Object nullState)<