优雅地关闭线程

发布于 2024-12-10 16:51:15 字数 1783 浏览 0 评论 0原文

在我正在开发的应用程序中,我有一个主窗体,它只是放置在那里并显示日志数据,以及一个在循环中自主完成工作的工作线程。

MyWorker worker = new MyWorker();
MainForm mainForm = new MainForm();

// Subscribe form to log event so log data gets displayed
worker.Log += mainForm.Log;

// Start the worker thread's MainLoop
new Thread(new ThreadStart(worker.MainLoop)).Start();

// Show the form (blocking)
Application.Run(mainForm);

// If we end up here, the form has been closed and the worker has to stop running            
worker.Running = false;

正如您所看到的,每当表单关闭时,工作线程都应该停止。工作线程看起来像这样:

public class MyWorker
{
    public String Running { get; set; }

    public MyWorker()
    {
        Running = true;
    }

    public void MainLoop()
    {

        while (Running)
        {

            DoExtensiveWork1();
            if (!Running) return;

            DoExtensiveWork2();
            if (!Running) return;

            DoExtensiveWork3();
            if (!Running) return;

            DoExtensiveWork4();
            if (!Running) return;

            DoExtensiveWork5();         
            if (!Running) return;

            // We have to wait fifteen minutes (900 seconds) 
            // before another "run" can be processed
            for (int i = 0; i < 900; i++)
            {
                Thread.Sleep(1000);
                if (!Running) return;
            }
        }
    }
}

正如您所看到的,我希望线程能够在连续工作操作之间切换时停止,而不是在操作内时停止。当操作(DoExtectiveWorkN)完成时,其状态和结果将保留在磁盘或数据库中,因此在操作正在进行时退出(例如,通过Thread.Abort) 不是一个选项。

然而,我发现我刚刚编写的这段代码令人反感,尤其是“等待循环”,它会休眠一秒 900 次,以防止线程在检测到 Running 之前空闲 15 分钟。已设置为false

我宁愿能够在完成一项工作后抛出某种事件来停止主循环。

任何人都可以指出我如何做到这一点的正确方向,或者如果因为我完全误解了线程而需要完全重写,请向我展示解释这些原则的地方?

In an application I'm developing, I have a main form that simply sits there and displays log data, and a worker thread that autonomously does the work in a loop.

MyWorker worker = new MyWorker();
MainForm mainForm = new MainForm();

// Subscribe form to log event so log data gets displayed
worker.Log += mainForm.Log;

// Start the worker thread's MainLoop
new Thread(new ThreadStart(worker.MainLoop)).Start();

// Show the form (blocking)
Application.Run(mainForm);

// If we end up here, the form has been closed and the worker has to stop running            
worker.Running = false;

As you can see, whenever the form is closed, the worker thread should be stopped. The worker looks like this:

public class MyWorker
{
    public String Running { get; set; }

    public MyWorker()
    {
        Running = true;
    }

    public void MainLoop()
    {

        while (Running)
        {

            DoExtensiveWork1();
            if (!Running) return;

            DoExtensiveWork2();
            if (!Running) return;

            DoExtensiveWork3();
            if (!Running) return;

            DoExtensiveWork4();
            if (!Running) return;

            DoExtensiveWork5();         
            if (!Running) return;

            // We have to wait fifteen minutes (900 seconds) 
            // before another "run" can be processed
            for (int i = 0; i < 900; i++)
            {
                Thread.Sleep(1000);
                if (!Running) return;
            }
        }
    }
}

As you can see, I want the thread to be able to stop when switching between successive work operations, but not when within an operation. When an operation (DoExtensiveWorkN) has finished, its status and results are persisted do disk or database, so quitting while an operation is in progress (by, for example, Thread.Abort) is not an option.

However, I find this code I've just written repulsive to look at, especially the "wait loop" which sleeps for one second 900 times, to prevent the thread from idling for 15 minutes before detecting Running has been set to false.

I'd rather be able to throw some kind of event to stop the main loop as soon as it's finished a piece of work.

Can anyone point me in the right direction how to do this, or if a total rewrite is required because I totally misunderstood threading, show me somewhere where those principles are explained?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦在深巷 2024-12-17 16:51:15

您可以显着地整理各个任务的运行和 15 分钟的等待循环。

我建议也许使用这样的东西:

public class MyWorker
{
    private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
    private readonly Action[] _workUnits;

    private bool Running
    {
        get { return !_stopEvent.WaitOne(0); }
    }

    public MyWorker()
    {
        _workUnits = new Action[]
        {
            DoExtensiveWork1,
            DoExtensiveWork2,
            DoExtensiveWork3,
            DoExtensiveWork4,
            DoExtensiveWork5
        };
    }

    public void Stop()
    {
        _stopEvent.Set();
    }

    public void MainLoop()
    {

        while (Running)
        {
            foreach (var workUnit in _workUnits)
            {
                workUnit();
                if (!Running) return;
            }           

            // We have to wait fifteen minutes (900 seconds) 
            // before another "run" can be processed
            if (_stopEvent.WaitOne(900000)) return;
        }
    }
}

然后在下一个适当的点停止该过程:

Worker.Stop();

You can tidy up both the running of the individual tasks and the 15 min wait loop considerably.

I'd suggest perhaps using something like this:

public class MyWorker
{
    private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
    private readonly Action[] _workUnits;

    private bool Running
    {
        get { return !_stopEvent.WaitOne(0); }
    }

    public MyWorker()
    {
        _workUnits = new Action[]
        {
            DoExtensiveWork1,
            DoExtensiveWork2,
            DoExtensiveWork3,
            DoExtensiveWork4,
            DoExtensiveWork5
        };
    }

    public void Stop()
    {
        _stopEvent.Set();
    }

    public void MainLoop()
    {

        while (Running)
        {
            foreach (var workUnit in _workUnits)
            {
                workUnit();
                if (!Running) return;
            }           

            // We have to wait fifteen minutes (900 seconds) 
            // before another "run" can be processed
            if (_stopEvent.WaitOne(900000)) return;
        }
    }
}

Then to stop the process at the next appropriate point:

Worker.Stop();
戏蝶舞 2024-12-17 16:51:15

我建议使用 System.Timers.Timer

您可以通过运行的东西来完成工作,而不是使用睡眠,您可以将计时器设置为在 15 分钟后再次关闭。

如果您想提前停止它,请调用某种中止方法(类似于设置 Running=true 变量)来停止计时器。

应该注意的是,每次计时器事件触发时,它都会启动一个新线程,因此您无需担心杀死后台线程。您的线程完成其处理运行,将计时器设置为在 15 分钟内运行,然后线程自然完成。如果您在等待期间中止,那么您只需摆脱计时器即可,无需进行更多清理。如果您在运行期间中止,则让运行完成,最后它会检查标志并且不会再次启动计时器,然后线程完成。

对于计时器,您需要将计时器设置为在进程结束时手动启动。另一种方法是让计时器每 15 分钟计时一次,但这意味着如果您的处理花费了 10 分钟,那么距离下一次运行只有 5 分钟。如果花费的时间超过 15 分钟,您可能就会遇到麻烦。手动重新启动计时器还可以保证处理在另一个正在运行时不会重新启动。

I would suggest using System.Timers.Timer.

You can do your work with the running thing and rather than using the sleep you can just set the timer to go off again in 15 minutes.

If you want to stop it early then call some kind of abort method (similar to setting your Running=true variable) that will stop the timer.

It should be noted that each time the timer event fires it will start up a new thread so you dont' need to worry about killing background threads. Your thread finishes its run of processing, sets the timer to run in 15 minutes and then the thread finishes naturally. If you abort during a wait then you just get rid of the timer and no more cleanup needed. If you abort during a run then you let the run finish and at the end it checks a flag and doesn't start the timer again and then the thread finishes.

For the timer you'll want to set the timer to start manually at the end of the process. The alternative is to have the timer ticking every 15 minutes but that would mean that if your processing took 10 minutes then it owuld only be 5 minutes before the next run. And if it took more than 15 minutes you may be in trouble. Also restarting the timer manually guarantees that the processing shouldn't restart while another is running.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文