C# 杀死一根线

C# 杀死一根线,c#,.net,multithreading,sleep,kill,C#,.net,Multithreading,Sleep,Kill,在我的应用程序中,我有一个持续运行的线程。通过使用Thread.Sleep(),函数每10分钟执行一次 我需要能够在用户单击按钮时终止此线程。我知道Thread.Abort()不可靠。我可以使用一个变量来停止线程,但由于它处于休眠状态,线程可能还要再等待10分钟才能自行终止 有什么想法吗?你为什么不改用计时器每十分钟安排一次任务呢。这将在线程池线程上运行您的代码,因此您不必自己管理它 有关更多详细信息,请参见课程。而不是Thread.Sleep使用System.Threading.ManualR

在我的应用程序中,我有一个持续运行的线程。通过使用Thread.Sleep(),函数每10分钟执行一次

我需要能够在用户单击按钮时终止此线程。我知道Thread.Abort()不可靠。我可以使用一个变量来停止线程,但由于它处于休眠状态,线程可能还要再等待10分钟才能自行终止


有什么想法吗?

你为什么不改用计时器每十分钟安排一次任务呢。这将在线程池线程上运行您的代码,因此您不必自己管理它


有关更多详细信息,请参见课程。

而不是
Thread.Sleep
使用
System.Threading.ManualResetEvent
。该方法有一个超时,就像
线程一样。Sleep
,除非先触发事件,否则线程将在该时间间隔内睡眠,返回值告诉您时间间隔是否已过或事件是否已设置。

一种可能是在十分钟内不睡眠。让它睡眠10秒钟,然后每60分钟醒来一次。那么在它停止之前,您只有10秒的延迟时间

旁白:这不一定是最好的解决方案,但可能是最快实现的。与所有可能性一样,在选择适合您的解决方案时,您应该进行成本/收益分析

如果10秒仍然太长,您可以将其进一步删除,但请记住,将其删除得太远可能会影响性能


你是对的,你不应该从外部杀死线程,如果你碰巧在它们锁定了一些没有在杀死时释放的资源时这样做,通常会导致灾难。线程应该始终对自己的资源负责,包括它们的生命周期。

基于Ben的答案,以下是帮助您解决问题的模式

using System.Threading;

public class MyWorker {
        private ManualResetEvent mResetEvent = new ManualResetEvent(false);
        private volatile bool mIsAlive;
        private const int mTimeout = 6000000;

        public void Start()
        {
            if (mIsAlive == false)
            {
                mIsAlive = true;
                Thread thread = new Thread(new ThreadStart(RunThread));
                thread.Start();
            }
        }

        public void Stop()
        {
            mIsAlive = false;
            mResetEvent.Set();
        }

        public void RunThread()
        {
            while(mIsAlive)
            {
                //Reset the event -we may be restarting the thread.
                mResetEvent.Reset();

                DoWork();

                //The thread will block on this until either the timeout
                //expires or the reset event is signaled.
                if (mResetEvent.WaitOne(mTimeout))
                {
                    mIsAlive = false; // Exit the loop.
                }
            }
        }

        public void DoWork()
        {
            //...
        } }

下面是一个示例,用户可以根据Brian的建议使用计时器来完成工作。根据需要使用启动/停止。要在处理完(程序)对象后清理该对象,请确保调用Dispose

注意,当你调用停止时,它将阻止计时器再次启动,但是在执行TimeRyELAP处理程序的中间,仍然可能有一个工作者线程,即停止计时器不停止当前正在执行的工作线程。

using System;
using System.Timers;

namespace TimerApp
{
    class Program : IDisposable
    {
        private Timer timer;

        public Program()
        {
            this.timer = new Timer();
            this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            this.timer.AutoReset = true;
            this.timer.Interval = TimeSpan.FromMinutes(10).TotalMilliseconds;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // TODO...your periodic processing, executed in a worker thread.
        }

        static void Main(string[] args)
        {
            // TODO...your app logic.
        }

        public void Start()
        {
            this.timer.Start();
        }

        public void Stop()
        {
            this.timer.Stop();
        }

        public void Dispose()
        {
            this.timer.Dispose();
        }
    }
}

有趣。你能告诉我更多的细节吗?这有点新。你仍然需要解决取消周期动作的问题。但现在它是禁用计时器而不是结束线程。我只需禁用计时器就可以取消该操作,不是吗?@whydna这种方法还突出了原始代码中的一个微妙错误:它不会每10分钟执行一次,而是每(10分钟+执行时间)执行一次。这取决于你正在做什么,可能重要,也可能不重要。此示例存在一个小问题。它等待超时时间以及
DoWork()
所花费的时间。如果工作时间超过一瞬间,则计时将停止。应从(上次工作开始时间+mTimeout)中扣除当前时间;如果是否定的,不要等待,只需回圈(作业花费的时间比mTimeout长)。这是真的,但由于OP使用睡眠,并且没有提到硬周期要求,我没有同步周期。这保留了计时行为,同时仍然允许外部线程按需终止循环。当然,在某些情况下,任何一种方法都是合适的——更不用说另一种情况,即如果当前期间的剩余持续时间低于某个阈值,您可能会跳过下一个期间。编辑:如果DoWork()在这段时间附近的任何地方,他将不得不在其他地方评估Mislave,以便尽早杀死它。这段代码只是按需中断“睡眠”。此外,您实际上应该在某个地方创建事件。对于类来说,仅仅声明一个变量并不足以创建一个实例。您可以始终从休眠等待连接状态中断()线程,让它读取一些变量,这些变量将告诉它中止。。。