not receiving a ThreadAbortException after thread.abort()

S

Stephan Steiner

Hi

I'm having some weird threading issues.. almost at random, if I dare change
a line of my code, the shutdown sequence gets messed up.
I'm using a thread to receive data from the network, that I suspend and
resume whenver needed. In order to properly shut down the program every
thread has to be aborted. So, I override OnClosing(CancelEventArgs e) in my
main GUI program, and have it perform the following on the thread:

if (thread.ThreadState == ThreadState.Suspended || thread.ThreadState ==
ThreadState.SuspendRequested)
{
thread.Resume();
this.shutdown = true;
}
thread.Abort();

In other words, if the thread is suspended or on the way to get suspended, I
have to resume it befrore shutting it down. I've been debugging this on and
off, and everything but the thread.Abort() line seems to work fine, the
thread is properly reactivated and the ThreadState changed to
ThreadState.Running, but then when I call thread.Abort(), the ThreadState is
changed to ThreadState.AbortRequested and then nothing happens. The program
finishes and hangs because the thread hasn't been properly aborted. I have
tried a while (thread.ThreadState == ThreadState.AbortRequested){} but the
infinite loop is never aborted and the ThreadState never changes which leads
me to believe that the event I'm waiting for is never thrown. Is there a way
to manually trigger that exception and make sure it gets delivered?

Stephan Steiner
 
C

Chris Capel

I would avoid aborting the thread entirely, and put a flag in your app that
the loop in your worker thread checks every time through that you set when
you want it to exit. This should do what you want without worrying about
aborting anything.

Chris

bool stop = false;
void MainThreadFunction {
while (!stop) {
//thread work
}
}

MainForm_Closing(object sending, CancelEventArgs e) {
stop = true;
//other stuff
}
 
D

Dave

Stephan Steiner said:
Dave

I did that and found out that there was indeed a thread.suspend scheduled
when I try to abort the thread. I try to re-enable the thread if the state
is suspended, but if the ThreadState is running when I make that check, and
then the thread gets suspended in the next timeslice, it will not be
re-enabled for the abort to be delivered.

Sounds like a classic race condition. I'd restructure the code so that the
signals were synchronized using events.

I've been looking into this, however, I came across another problem: I'm
receiving packets, using ReceiveFrom which is blocking. Thus, even if a have
a WaitHandle.WaitAny or a WaitOne on the abovementioned ResetEvents, that
line is never executed because the ReceiveFrom is just sitting there,
blocking the thread. So, somehow I need a way to abort the ReceiveFrom and
restart the thread loop once I have set my ResetEvents. Is there any such
mechanism?
Typically you can close the socket that the ReceiveFrom is waiting on. This
should cause it to return from the call with an error or an exception
indication (I haven't used the sockets classes yet so I don't know which
form it will take).

Using an event to synchronize shutdown notifications usually works well. If
you combine the events with closing the sockets the thread is blocked on it
should work. You can also take a look at Rich Blum's book on network
programming in C#. I started reading it but until I have a project where I
need to learn more about it'll probably stay on the shelf - there should be
some examples in there on how you can structure this code. What you are
doing is pretty standard, vanilla network programming.
 
S

Stephan Steiner

Dave
Typically you can close the socket that the ReceiveFrom is waiting on. This
should cause it to return from the call with an error or an exception
indication (I haven't used the sockets classes yet so I don't know which
form it will take).

That might well be, but I've been thinking about the next level already -
the reason why I haven't used events so far: Basically my program does (or
should do;) the following: permanently listen on the socket and forward
packets to a processing method in the UI thread domain (the receiver thead
fires an event to do that). Then once packets start coming in, they will
contain an indicator when the next databurst is to be expected, and as soon
as the first packet containg that info is received, a timer is started which
will reactivate (atm resume) the receiver thread at the appropriate time. At
the same time, there's another timer that is triggered periodically while
the receiver is active and which decides whether the thread should stay
active or not (be suspended). The decision criteria is whether new packets
have been received for a certain period or not. As if this wasn't enough,
disabling the receiver can also be triggered from the processing methods in
the GUI thread domain. So if I were to remove thread.Suspend and Resume and
use a ResetEvent class, I might be able to abort the ReceiveFrom by closing
the socket, which is okay when shutting down the program, but if I am to use
ResetEvents and WaitHandles to decide whether the thread receives incoming
packets, or shuts down, I cannot simply disconnect the socket to get to the
next WaitOne call in the receiver thread, as setting up a socket takes a lot
of time and has some issues (a buffering issue when you start sending /
receiving large amounts of data immediately after setting up the socket..
I've discussed that with Rich Blum already and I ended up with a small
workaround consisting of doing one send/receive operations when creating the
class containing the socket, as afterwards data bursts are no longer a
problem). I've just verified this, thread.Interrupt doesn't help either,
since ReceiveFrom doesn't block the thread.

Stephan
 
D

Dave

Ths may simply be a case where I don't understand what you are trying to
accomplish. I still don't see why you need to suspend/resume the threads,
especially the one you call the receiver thread. In other words, what is the
basic problem you are trying to solve by suspending/disabling the thread? Is
this for buffer overrun control?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top