正常关闭线程

时间:2011-10-20 10:09:35

标签: c# multithreading

在我正在开发的应用程序中,我有一个主要表单,它只是位于那里并显示日志数据,以及一个自动完成工作的工作线程。

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

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

然而,我发现这段代码我刚刚写了一些令人厌恶的代码,特别是“等待循环”,它休眠了900秒,以防止线程在检测到Running之前空转15分钟已设置为false

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

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

2 个答案:

答案 0 :(得分:14)

你可以大大整理各个任务的运行和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();

答案 1 :(得分:0)

我建议使用System.Timers.Timer

你可以使用正在运行的东西进行工作,而不是使用睡眠,你只需将计时器设置为在15分钟后再次启动。

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

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

对于计时器,您需要将计时器设置为在过程结束时手动启动。另一种方法是让计时器每15分钟滴答一次,但这意味着如果你的处理需要10分钟,那么它只能在下一次运行前5分钟。如果花了超过15分钟,你可能会遇到麻烦。另外,手动重新启动计时器可确保在另一个计算机正在运行时不应重新启动。