Why could a suspended thread leak?

  • Thread starter Thread starter beginwithl
  • Start date Start date
B

beginwithl

hi

1) “Aborting or suspending an active thread is generally considered a
bad idea. When you do so, there is a chance (however small) that a
thread could “leak” its workload when disturbed or terminated.”

What is considered a workload? And why could suspended/aborted thread
leak?



2)

a) As far as I understand, even if you give a thread T1 highest
priority, CLR won’t necessarily instruct thread scheduler to give it
such priority? How will we know whether CLR decided not to give T1
highest priority?


b) But even if CLR does instruct thread scheduler to give it highest
priority, but at some point thread scheduler is preoccupied with a
given task and thus decides to give more time to other thread with
lower priority, will it in that case also change the level of T1’s
priority accordingly, or will it leave T1’s priority set to max and
just threat it as being of lower priority?



3) If we, inside primary thread T0, use a delegate to invoke some
method M1 in an asynchronously manner, then M1 will be called on a
separate thread T1. When M1 is finished, T1 can use AsyncCallback
delegate ( which in turn calls some method M2 ) to inform T0 when
the task is finished.

But I’d argue that AsyncCallback delegate instance doesn’t really
inform calling thread ( T0 in our example ) whether asynchronously
invoked method M1 is completed. All Asyncallback delegate does is
calling method M2 ( M2 is invoked inside thread T1 ). Perhaps
programmer can inside M2 implement some sort of mechanism, which
somehow informs T0 to stop whatever it is doing, because M1 has
completed. But for AsyncCallback delegate to really inform the
calling thread M1 has finished, it would have to invoke M2 inside T0,
which it doesn’t! Correct?


thank you
 
hi Pete


Impossible to answer without a specific implementation in mind.  But, one  
example would be a thread that uses unmanaged resources, which aren't  
subject to garbage collection management.  If you abort a thread that is  
using something like this, it may not have a chance to clean up those  
resources.  

By ‘cleaning up resources’ you mean, for example, closing connection
to some source, or destroying the memory some source occupies etc?

Or if you're maintaining state in some sort of data structure  
that is reachable even without the thread executing, a similar thing could  
happen.

* By ‘data structure being reachable’ you mean that when thread is in
suspended state, it doesn’t hold locks ( meaning locks aren’t in
effect when suspended ) on that data structure and thus data structure
could be corrupted by some other thread or app?

* I assume it is this data structure that is considered a workload?

* Thus leaking essentially means exposing data to other threads?
That said, I think that the advice is somewhat misguided.  You can try to  
code the thread to catch exceptions, and in general if you do things  
correctly, you can probably guarantee that you clean up after yourself.  
The big problem with using abort or suspend on a thread is that there's no  
effective way to control _where_ in the thread those actions occur, which 
significantly increases the difficulty in guaranteeing that the thread's  
code is correct, which in turn significantly increases the chances of a  
bug getting into the code.

Whatever the reason, just "don't do that".

I shouldn’t suspend thread even if I code it so that it catches
exceptions?


It's not that the CLR wouldn't give it the priority, it's that the OS  
wouldn't.

I don't know that you can determine this, not via .NET.  

Say I set thread’s priority to “Highest”, but OS decides to assign it
another priority. Now if I check at run time what thread’s priority
is, the priority property will return value “Highest”, even though its
actual priority is of some other level?
The thread scheduler's algorithms for managing priority inversion and  
thread starvation don't permanently change a thread's priority.
In other words, if thread scheduler decides that another thread T2
should get higher priority than thread T1 ( until some task on T2 is
completed ), then it changes T1’s priority to some lover level, and
when T2 finishes some given task, thread scheduler changes T1’s
priority level back to its original value?


thanx mate
 
hi Pete


If you abort a thread that is using something like this, it may not have a chance
to clean up those resources. Or if you're maintaining state in some sortof data
structure that is reachable even without the thread executing, a similar thing
could happen.

* This is utterly confusing. I do realize that it’s hard to say
anything on the subject without having specific example in mind, but
still…

Say we have threads T1 and T2 and piece of data called D. In T1 we
have a reference variable V1 pointing to D, while in T2 variable V2
also points to D.
So the argument is, that if we don’t kill any of the two threads, then
D may at some point become unreachable and subject to garbage
collector. But if we do kill T1, then D may never become unreachable,
even when not needed anymore.
So in other words, if we didn’t kill T1, then V2 would at one point go
out of scope, and thus D would become unreachable ( provided no other
variable pointed to D). But if we kill/suspend T1, then V2 may never
go out of scope. But how can existence of T1 have any effect on when
variable in some other thread goes out of scope?

* I know leaking takes up memory, but is there any other reason why it
is considered bad?
It's a thread abort that would cause an exception.  Suspending a thread 
just pauses it temporarily.

But, no...you shouldn't suspend a thread.  You have no way to control  
where in the thread it will get suspended, and that makes it a lot easier 
to wind up with hard-to-solve bugs.  Instead, use a regular thread  
synchronization mechanism that will cause the thread to block in a  
predictable place, in a predictable state.

* If I understand you correctly, you are saying that when you call
Suspend() on a thread, thread won’t necessarily go into suspended
state right away, but may instead execute few more statements that
follow the Suspend() call? Similarly, if you try to kill a thread, it
won’t necessarily be killed right away and thus few more statements
following Abort() call may also get executed?

* I also assume that if suspended/killed thread has a lock on
something, it won’t release that lock when suspended or killed?

Probably, but I don't know.  In spite of the warning in the documentation,  
I'm not aware of any particular examples of where this would happen.

That said, you should not generally be changing a thread's priority  
anyway.  And if you do change a thread's priority, almost always the only  
right way to change it is to lower it.

That's a broad generalization, but the only exceptions are situations  
where the person who is writing the code knows so much about threading  
that they wouldn't have to ask what the exceptions to the rule are.  To 
make things worse, the most likely reason that someone who is relatively  
new to threaded programming wants to raise their thread's priority is in  
situations when they really should in fact be lowering it instead.

I would say that there aren't many places in the OS where if you have to  
ask how to do something, you probably shouldn't be doing it.  But this  
would be one of them.  Don't raise thread priorities.
Will remember that

If you really want to get into the nuts and bolts of thread scheduling on 
Windows, I recommend reading the details in the documentation, or in a  
good book like Joe Duffy's "Concurrent Programming on Windows".  

This word gets tossed around a lot when talking about threads. Is
concurrent programming another word for a thread programming and thus
the two terms can be used interchangeably, or does it mean something
else?

Thus, does a book on threading talk about something else than a book
on concurrent programming?

thanx mate
 
hi

uh

[...]
Say we have threads T1 and T2 and piece of data called D. In T1 we
have a reference variable V1 pointing to D, while in T2 variable V2
also points to D.

Threads don't have variables. Classes do.

Some variables are found in methods (i.e. local variables). These exist
only so long as the thread where the method was called exists. Other
variables live longer, either because they are contained within an
instance of an object that itself lives longer, or because they are static
variables.
Uhm, I know that :(
For the sake of argument, let's assume that you are talking about local
variables, since this is the closest thing to a thread having a variable.

(For the sake of this discussion, I am also ignoring "thread local
storage", which is in fact exactly a way of a thread having a
variable...it would only confuse things further to drag that OS feature
into the discussion).


That's exactly the opposite of what happens. Assuming _either_ thread T1
or thread T2 continues to exist, and their variable V1 or V2 continues to
exist, then object D remains reachable, and won't be collected.
That also seemed most logical to me, but I thought you were implying
just the opposite with the following:

"Or if you're maintaining state in some sort of data structure
that is reachable even without the thread executing, a similar thing
could
happen. "

* So with “is reachable even without the thread executing” you were
referring to objects “local” ( thus no other thread references them )
to the aborted/suspended thread, which ( even though there are no
longer any references to them ) are still somehow reachable?

If both threads T1 and T2 are aborted, and the only variables referencing
object D were the local variables V1 and V2 in those threads, then once
both threads have been aborted, object D is no longer reachable and is
eligible for garbage collection.

But that's not the kind of situation a warning against aborting a thread
is talking about. The threads may be responsible for maintaining other
variables, such as static variables or unmanaged resources managed
somehow. In those cases, those things don't automatically go away when
the threads are aborted. Only explicit code within the thread could clean
up those resources, and if you abort the thread, it may not be able to do
that.
And in such cases ( where a thread hasn’t cleaned up the resources )
objects may never become unreachable, even though app doesn’t
reference them anymore?

But that's not the kind of situation a warning against aborting a thread
is talking about. The threads may be responsible for maintaining other
variables, such as static variables or unmanaged resources managed
somehow. In those cases, those things don't automatically go away when
the threads are aborted. Only explicit code within the thread could clean
up those resources, and if you abort the thread, it may not be able to do
that.
Uhm, aren’t static variables in a way always reachable ( I realize you
had something different in mind, but I don’t know how else to ask ),
so why would that be considered a problem?

The reason you don't know the state of the thread when using Abort() or
Suspend() is that there's nothing that would let your code know what
instruction the thread being aborted or suspended is executing. Keeping
in mind also that the thread executes instructions, not statements, so you
could even wind up aborting or suspending a thread mid-statement.

* But if thread only gets aborted/suspended when it executes Abort/
Suspend statement, then I don’t see how there could be a danger of a
thread being suspended in a mid-statement ( the following code is
inside a thread we wish to suspend ):

int i = 6 + 100; // 1. statement
Thread.Suspend(); // 2.statement
int u = i + 100; // 3.statement

To my understanding thread first executes 1. statement, then it reads
second statement, which “instructs it” to become suspended. And thus
the thread immediately stops reading any more statements and gets into
suspended state?!


* Now only way I can think of how thread would become suspended in the
middle of the some statement is if thread did execute the second
statement, but instead of going into suspended state right then and
there, it still went on to execute 3. statement and in the middle of
executing this third statement “realized” it must become suspended.

But since I statements get executed right away the above can't be
true



It depends on the lock. If you're using the "lock" statement, that has an
implicit "finally" clause that will ensure Monitor.Leave() is called when
an exception happens. Other locking techniques may not be so robust
(though it's possible to code them in a more robust way, by writing an
explicit "finally" for example, my point is that aborting threads makes it
much more difficult to get things right).

For suspending a thread, yes...there's no way for the thread to know this
occurs and so a lock the thread had acquired will in fact be held
indefinitely as long as that thread is suspended.

* How can a thread T1 not know when it will get aborted? It will get
aborted the moment is reads and executes the statement Thread.Abort();
It’s not like some code existing outside T1 executes the Abort()
statement and that way “remotely” aborts T1?!

* In any case, since Suspend/Abort statement is present inside the
thread we wish to abort, then programmer writing this code could
easily release a lock ( on whatever resource it is locking on ) right
before calling Suspend/Abort?! So why all the fuss??




thanx mate
 
hi Pete

[...]
"Or if you're maintaining state in some sort of data structure
that is reachable even without the thread executing, a similar thing
could
happen. "
* So with “is reachable even without the thread executing” you were
referring to objects  “local” ( thus no other thread references them )
to the aborted/suspended thread, which  ( even though there are no
longer any references to them ) are still somehow reachable?

No, I'm referring to objects reachable via some other data structure.

It would be useful for you to not mix "aborted" and "suspended".  Those 
are two very different scenarios, and you can't really apply the same  
reasoning to each.

For aborted threads, the stack goes away.  Local variables no longer  
exist, so the only way an object referenced by the thread could still be  
reachable is if there's a reference somewhere else.  Such in a static  
variable, or some data structure that is itself referenced (directly or  
indirectly) by a static variable.

So if thread T1 wasn’t aborted, then T1 would be able to somehow
manage to make the object to become unreachable ( when not wanted
anymore )?
But if thread is aborted, then that may not happen and thus object is
still reachable ( app still references it via some static variable
or… ) even when not needed/wanted anymore? And that is considered a
leak

For suspended threads, the stack remains.  Objects remain reachable simply  > by virtue of being referenced even simply within the stack as local  
variables.  If a thread had a reference to an object before it's  
suspended, it continues to have a reference to the object after it's  
suspended.

And why would that be considered a problem ( why would we call it
leaking )? Thread will simply “make” object unreachable when it is
resumed?!


False predicate results in a trivially true "if/then" statement.

In other words, it's simply not true that a "thread only get  
aborted/suspended when it executes Abort()/Suspend() statement".  In fact,  
the only interesting uses of those methods is when they are called by a  
thread other than the one being aborted or suspended.

And hopefully with that, you understand why using those methods can result  
in unpredictable results.

yep :)



thank you
 
Back
Top