Reputation: 23732
I have a Timer
which has to cancel a Thread
if it needs too much time.
System.Timers.Timer timer_timers = new System.Timers.Timer();
Thread thread = new Thread(startJob);
thread.Name = "VICTIM_THREAD";
when starting the Thread
method I start the Timer
and pass the current Thread to the event as parameter.
public void startJob()
{
Debug.WriteLine("Name: " + Thread.CurrentThread.Name);
timer_timers.Elapsed += (sender, e) => T_Elapsed(sender, e, Thread.CurrentThread);
timer_timers.Interval = 5000;
// Start simulation process
while (true)
{
Thread.Sleep(700);
Debug.WriteLine("Thread: " + Thread.CurrentThread.Name + " ALIVE: " + thread.IsAlive);
}
}
Timer event:
private void T_Elapsed(object sender, ElapsedEventArgs e, Thread currentThread)
{
// EDIT: show the correct NAME! of the thread
Debug.WriteLine("Name: " + currentThread.Name);
System.Timers.Timer tim = sender as System.Timers.Timer;
currentThread.Abort(); // <-- this line throws exception
if (tim != null)
{
tim.Stop();
}
}
But the Abort
call throws me an Exception:
'Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack'
and the thread remains alive.
If I start the timer before the startJob()
and pass the thread directly it works fine.
public void startThread()
{
timer_timers.Elapsed += (sender, e) => T_Elapsed(sender, e, thread);
timer_timers.Interval = 5000;
timer_timers.Start();
thread.Start();
}
public void startJob()
{
// Start simulation process
while (true)
{
Thread.Sleep(700);
Debug.WriteLine("Thread: " + Thread.CurrentThread.Name + " ALIVE: " + thread.IsAlive);
}
}
Question: Why does the Thread.CurrentThread
version not work? is it because I would also have to abort the timer thread? What am I missing here?
Answers I found to this exception like this and this are from different context and don't really help me to understand exactly why.
EDIT: I know that this is the wrong way to abort or cancel a thread. The job it is supposed to do is to open a SerialPort. But once every ~200-th time the thread will just never return and I need to kill it nevermind the consequences. the simulation while loop is may be a bad example.
Upvotes: 1
Views: 1327
Reputation: 117029
Don't ever call Thread.Abort
. Here's how to do it properly:
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var t = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write(".");
Thread.Sleep(500);
}
}, token);
var timer = new System.Timers.Timer();
timer.Interval = 5000;
timer.Elapsed += (s, e) => tokenSource.Cancel();
timer.Enabled = true;
The reason that your code appears to work in the second case is that you are capturing the thread before the call to T_Elapsed
. In the first case you are requesting the current thread only when the time Elapsed
event is called (and at that point it isn't the calling thread, it's the callee).
Upvotes: 4
Reputation: 44181
As noted in the comments, you should not be using Abort
. Even if you do, here is the issue with the way you're using it:
Timers don't run on your thread. They run on the thread pool thread. Hence Thread.CurrentThread
used in your lambda is going to be that thread pool thread.
Here is what you should be doing if you want to abort the thread which is creating the timer: Capture the thread in a variable outside the lambda.
Thread myThread = Thread.CurrentThread;
timer_timers.Elapsed += (sender, e) => T_Elapsed(sender, e, myThread);
But you should be finding another way to terminate your thread more gracefully, or to rework your code to not need explicit threading.
Upvotes: 5