1

如果需要太多时间,我有一个Timer必须取消的。Thread

System.Timers.Timer timer_timers = new System.Timers.Timer();
Thread thread = new Thread(startJob);
thread.Name = "VICTIM_THREAD";

启动Thread方法时,我启动Timer并将当前线程作为参数传递给事件。

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);
    }            
}

定时器事件:

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();
    }

}

但是这个Abort电话给我抛出了一个异常:

'无法评估表达式,因为代码已优化或本机框架位于调用堆栈顶部'

并且线程仍然活着。如果我在 之前启动计时器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);
    }            
}

问题:为什么Thread.CurrentThread版本不工作?是因为我还必须中止计时器线程吗?我在这里想念什么?

我发现这个例外的答案来自不同的上下文,并不能真正帮助我理解为什么。

编辑:我知道这是中止或取消线程的错误方法。它应该做的工作是打开一个 SerialPort。但是每隔约 200 次,线程就永远不会返回,我需要杀死它,不管后果。模拟while循环可能是一个不好的例子。

4

2 回答 2

5

如评论中所述,您不应该使用Abort. 即使你这样做了,这也是你使用它的方式的问题:

计时器不在您的线程上运行。它们在线程池线程上运行。因此Thread.CurrentThread,在您的 lambda 中使用的将是那个线程池线程。

如果您想中止创建计时器的线程,您应该执行以下操作:在 lambda 之外的变量中捕获线程。

Thread myThread = Thread.CurrentThread;
timer_timers.Elapsed += (sender, e) => T_Elapsed(sender, e, myThread);

但是您应该找到另一种更优雅地终止线程的方法,或者重新编写代码以不需要显式线程。

于 2016-07-07T13:58:20.147 回答
4

永远不要打电话Thread.Abort。以下是如何正确执行此操作:

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;

您的代码在第二种情况下似乎工作的原因是您在调用T_Elapsed. 在第一种情况下,您仅在调用时间事件时才请求当前线程Elapsed(此时它不是调用线程,而是被调用者)。

于 2016-07-07T14:17:03.387 回答