I am creating an application that has a thread which constantly moves the contents of one folder to another (Using Visual Studio, Compact Framework)

I start the thread like this

public static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
		/// 


        [MTAThread]
        public static void Main()
        {

		SendXML ThreadToSendXML = new SendXML();
			Thread2 SecondaryThread = new Thread2(ThreadToSendXML.Run);
			SecondaryThread.Start();

            Application.Run(new frmLogin());
        }
    }

This immediately executes the thread when the program compiles. I then have the thread defined within a class called "Send XML".

public class SendXML
	{
		/// <summary>
		/// Variable to hold the temporary directory
		/// </summary>
		public string TempDirectory = @"\Program Files\smartdeviceproject1\TempXML\IntoContainer\";

		/// <summary>
		/// Variable to hold the send folder filepath
		/// </summary>
		public string SendDirectory = @"\Program Files\smartdeviceproject1\SendXML";

		/// <summary>
		/// Lock covering stopping and stopped
		/// </summary>
		readonly object stopLock = new object();
		/// <summary>
		/// Whether or not the worker thread has been asked to stop
		/// </summary>
		public static bool stopping = false;
		/// <summary>
		/// Whether or not the worker thread has stopped
		/// </summary>
		public static bool stopped = false;

		/// <summary>
		/// Returns whether the worker thread has been asked to stop.
		/// This continues to return true even after the thread has stopped.
		/// </summary>
		public bool Stopping
		{
			get
			{
				lock (stopLock)
				{
					return stopping;
				}
			}
		}

		/// <summary>
		/// Returns whether the worker thread has stopped.
		/// </summary>
		public bool Stopped
		{
			get
			{
				lock (stopLock)
				{
					return stopped;
				}
			}
		}

		/// <summary>
		/// Tells the worker thread to stop, typically after completing its 
		/// current work item. (The thread is *not* guaranteed to have stopped
		/// by the time this method returns.)
		/// </summary>
		public void Stop()
		{
			lock (stopLock)
			{
				stopping = true;
			}
		}

		/// <summary>
		/// Called by the worker thread to indicate when it has stopped.
		/// </summary>
		void SetStopped()
		{
			lock (stopLock)
			{
				stopped = true;
			}
		}

		/// <summary>
		/// Main work loop of the class.
		/// </summary>
		public void Run()
		{
			try
			{
				while (!Stopping)
				{
					FileInfo[] rgFiles;
					///Defines the contents of the TempDirectory as "di"
					DirectoryInfo di = new DirectoryInfo(TempDirectory);

					rgFiles = di.GetFiles("*.xml");


					foreach (FileInfo s in rgFiles)
					{
						string SourceFile = s.Name;
						string TargetFile = Path.Combine(SendDirectory, SourceFile);
						File.Move(s.FullName, TargetFile);
					}
					Thread.Sleep(250);		
				}
			}
			finally
			{
				SetStopped();
			}
		}

	}

This runs fine and does everything I want it to, the problem occurs when I want to exit the program, the threads keeps running (presumerbly because I haven't joined it to the main program thread). I've tired Application.Exit() on a button's click event but to no avail (I saw it kept moving files even after the UI had exited). In short, I need to either join or terminate the thread "SecondaryThread" from another class. Any help would be much appreciated, I am rather new to threading.

public partial class frmMainMenu : Form
    {

        public frmMainMenu()
        {
            InitializeComponent();
        }

         private void btnLogout_Click(object sender, EventArgs e)
        {
				Application.Exit();
        }


    }

This is where I wish to join all the threads and terminate them all.

>This is where I wish to join all the threads and terminate them all.

private void btnLogout_Click(object sender, EventArgs e)
        {
               SendXML.stopping=true;
   	       Application.Exit();
        }

OR

Declare SecondaryThread as a static field in Program class.

......
        public static Thread2 SecondaryThread;
        [STAThread]
        static void Main()
        {

            SendXML ThreadToSendXML = new SendXML();
            SecondaryThread= new Thread(ThreadToSendXML.Run);
          ....
      }

and use join method.

private void button1_Click(object sender, EventArgs e)
        {
            SendXML.stopping = true;
            Program.SecondaryThread.Join();
            Application.Exit();
        }
///Creates a new instance of the SendXML class 
			SendXML ThreadToSendXML = new SendXML();
			///Creates a new thread to send XMLS
			Thread SecondaryThread = new Thread(ThreadToSendXML.Run);
			///Starts the thread
			SecondaryThread.Start();

			///Runs the main application
            Application.Run(new frmLogin());

			///Stops the thread which transmits XML files
			ThreadToSendXML.Stop();

Would stopping it here, like this, be just as effective?

...
///Runs the main application
Application.Run(new frmLogin());
///Stops the thread which transmits XML files
ThreadToSendXML.Stop();

Would stopping it here, like this, be just as effective?

Yes.

Application.Run(form) doesn't return until the form is closed. So it would actually be a perfect place to end any background threads started with an application scope. Although you may still want to join the threads just to make sure that the background thread as stopped before the Main method returns.

If your problem is solved you should mark it solved.

An alternate is to put an if statement in your move loop.

if (!Stopping) File.Move(s.FullName, TargetFile);

It would finish the last move of files and then just loop through everything without doing additional work and then leave. Since you have a try block, before the loop you could declare:

int zero = 0;

and after the move and still in the loop

if (Stopping) zero = 1/zero; //Intentionally aborting the loop

Not sure what stopping a thread in the middle of a move would do. (Purists would have you throw an exception instead of intentionally blowing up.)

Edited 6 Years Ago by kplcjl: Added PS

FYI You have public static bool stopped = false;
being set to true by an instance. Note that if you have multiple instances, this would be set to true in one instance where another instance could still be running. You might want to set that as an instance get property and a private bool so no-one else can muck with it. If you have multiple instances then you could wait for the final move to finish before you exit.

This question has already been answered. Start a new discussion instead.