关闭任务运行的表单

时间:2012-09-21 14:14:49

标签: c# winforms task task-parallel-library

我有一个WinForms应用程序,它包含一个主UI线程和4个任务。我的主窗体有一个私有成员级变量,如下所示:

private bool keepThreadsRunning = false;

在我的主表单的Load()事件中,我有以下内容:

keepThreadsRunning = true;
var task1Worker = Task.Factory.StartNew(() => DoStuff1());
var task2Worker = Task.Factory.StartNew(() => DoStuff2());
var task3Worker = Task.Factory.StartNew(() => DoStuff3());
var task4Worker = Task.Factory.StartNew(() => DoStuff4());

在我的每个DoStuff()方法中,我基本上都有这个:

while (keepThreadsRunning)
{
  // do work here
  Thread.Sleep(30000); // a couple of my tasks only need to run every 30 seconds or so
}

最后,在我的Form_Closing()事件处理程序中,我有以下内容:

keepThreadsRunning = false;
this.Close();

在任务管理器中查看我的应用程序时,似乎当我关闭表单时该过程结束但我对这四个任务有点困惑。我是否调用this.Close()确实导致这些任务终止(即使它们在Thread.Sleep()调用时发生)?还有一种更好的方法来实现这一点,而不是我现在正在编码的方式吗?

编辑 - 我简要介绍了任务取消(当我的应用程序退出时),但我的理解是我的任务需要定期检查取消令牌以确定它们是否已被取消。鉴于我的一些任务需要每30秒运行一次,我无法弄清楚我是如何实现30秒等待(当前是Thread.Sleep())并且仍然要检查取消令牌。

3 个答案:

答案 0 :(得分:3)

不是使用布尔值和Thread.Sleep(),而是使用WaitHandle,特别是ManualResetEvent,如下所示:

var threadTerminationHandle = new ManualResetEvent(false);

在你的主题中:

do {
  // do work here
} while (!threadTerminationHandle.WaitOne(TimeSpan.FromSeconds(30))

这将等到设置WaitHandle或30秒后,以较早者为准。

以您的形式:

threadTerminationHandle.Set();
Close();

答案 1 :(得分:2)

首先,关闭主UI线程将终止您的其他任务。如果您需要它们继续运行,可以考虑在单独的控制台应用程序或Windows服务中运行它们。

即使您在运行完需要运行的方法时找到了延迟关闭表单的方法,这只有在最终用户以您希望的方式关闭表单时才有效,并且Windows是Windows一百万个关闭应用程序的方法,因此不能保证这将起作用。

为了每隔x秒异步运行一个方法,你可以使用一个计时器来完成整个过程,如下所示:

using System;
using System.Timers;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var timer1 = new System.Timers.Timer { Interval = 30000, Enabled = true };
            var timer2 = new System.Timers.Timer { Interval = 20000, Enabled = true };
            var timer3 = new System.Timers.Timer { Interval = 10000, Enabled = true };
            var timer4 = new System.Timers.Timer { Interval = 5000, Enabled = true };

            timer1.Elapsed += timer1_Elapsed;
            timer2.Elapsed += timer2_Elapsed;
            timer3.Elapsed += timer3_Elapsed;
            timer4.Elapsed += timer4_Elapsed;
        }

        void timer4_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer3_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer2_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer1_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }
    }
}

答案 2 :(得分:2)

当您关闭应用程序时,任务将相应关闭,因为任务是在线程池中的后台线程下处理的。因此,您无需定期检查取消令牌以确定它们是否已被取消