简体   繁体   English

从计时器事件中止线程

[英]Aborting thread from timer event

I have a Timer which has to cancel a Thread if it needs too much time. 我有一个Timer ,如果需要太多时间,则必须取消Thread

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. 当启动Thread方法时,我启动了Timer并将当前Thread作为参数传递给事件。

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: 但是Abort调用使我抛出异常:

'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. 如果我在startJob()之前启动计时器并直接传递线程,则它可以正常工作。

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? 问题:为什么Thread.CurrentThread版本不起作用? 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. 它应该做的工作是打开一个SerialPort。 But once every ~200-th time the thread will just never return and I need to kill it nevermind the consequences. 但是,每隔200次,线程将永远不会返回,而我需要杀死它却永远不会忘记后果。 the simulation while loop is may be a bad example. 模拟while循环可能是一个不好的例子。

As noted in the comments, you should not be using Abort . 如评论中所述,您不应使用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. 因此,您的lambda中使用的Thread.CurrentThread将成为该线程池线程。

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. 如果要中止正在创建计时器的线程,请执行以下操作:在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. 但是您应该寻找另一种方式来更优雅地终止线程,或者重新编写代码以不需要显式线程。

Don't ever call Thread.Abort . 永远不要调用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 . 您的代码在第二种情况下似乎可以正常工作的原因是,您正在调用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). 在第一种情况下,仅在调用time Elapsed事件时才请求当前线程(此时,它不是调用线程,而是被调用者)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM