Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closing form with tasks running

I have a WinForms application that consists of a main UI thread and 4 tasks. My main form has a private member level variable like this:

private bool keepThreadsRunning = false;

In the Load() event of my main form, I have the following:

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

Inside of each of my DoStuff() methods, I basically have this:

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

Lastly, in my Form_Closing() event handler, I have the following:

keepThreadsRunning = false;
this.Close();

Watching my application in task manager, it appears that the process is ending when I close my form but I'm a little confused about the four tasks. Is my call to this.Close() really causing those tasks to terminate (even if they're in the Thread.Sleep() call when it happens)? And is there a better way of accomplishing this than the way I'm coding it right now?

EDIT - I've looked briefly at task cancellation (when my app exits) but my understanding is that my tasks would need to periodically check the cancellation token to determine if they've been cancelled. Given that some of my tasks need to run every 30 seconds, I couldn't figure out how I'd implement that 30s wait (currently a Thread.Sleep()) and still have the task be checking the cancellation token.

like image 740
bmt22033 Avatar asked Sep 21 '12 14:09

bmt22033


2 Answers

Rather than using a boolean and Thread.Sleep(), use a WaitHandle, specifically a ManualResetEvent, created like this:

var threadTerminationHandle = new ManualResetEvent(false);

In your thread:

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

This will wait until the WaitHandle is set, or 30 seconds elapses, whichever is sooner.

In your form:

threadTerminationHandle.Set();
Close();
like image 125
Tim Rogers Avatar answered Sep 18 '22 06:09

Tim Rogers


First of all, closing the main UI thread will terminate your other tasks. If you need them to keep running, maybe consider running them in a seperate Console Application, or a Windows Service.

Even if you found a way to delay the closing of the form while you finish running the methods you need to run, this would only work if the end user closed the form in the way you wanted, and Windows being Windows there are a million and one ways to close an application so there is no guarantee that this will work.

For running a method asynchronously every x amount of seconds, you could just use a timer for the whole thing, like so:

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
        }
    }
}
like image 27
JMK Avatar answered Sep 18 '22 06:09

JMK