My program starts 5 different threads when it is opened. One or more of them is not stopping correctly and is causing my program to remain alive even after the main form has closed. Before I go through trying to find which one is doing it is there some way I can just force every thread to immediately stop when the program is starting to close? I know it's bad technique to force something to stop but none of the threads are actually doing anything that could hurt if it's interrupted. All of them check each second to see if they need to do something so most of the time they're doing nothing at all.

Recommended Answers

All 19 Replies

Do you have references to the threads? If so, call Thread.Abort() on them. If not before you start the thread set it as a background thread (Thread.IsBackground = true). Background threads cannot prevent the main thread from closing (like your forground threads are doing).

My program starts 5 different threads when it is opened. One or more of them is not stopping correctly and is causing my program to remain alive even after the main form has closed. Before I go through trying to find which one is doing it is there some way I can just force every thread to immediately stop when the program is starting to close? I know it's bad technique to force something to stop but none of the threads are actually doing anything that could hurt if it's interrupted. All of them check each second to see if they need to do something so most of the time they're doing nothing at all.

set thread background property to true and/or implement IDisposable

My program starts 5 different threads when it is opened. One or more of them is not stopping correctly and is causing my program to remain alive even after the main form has closed. Before I go through trying to find which one is doing it is there some way I can just force every thread to immediately stop when the program is starting to close? I know it's bad technique to force something to stop but none of the threads are actually doing anything that could hurt if it's interrupted. All of them check each second to see if they need to do something so most of the time they're doing nothing at all.

also to ensure that the thread(s) task is complete before the main thread finishes you can use yourThread.Join()

Oups..I'm working with Background Workers not Threads, I call them both threads. My bad. :D

Oups..I'm working with Background Workers not Threads, I call them both threads. My bad. :D

hey wildBamaBoy backGround worker threads background property "should" set to true therefore ending once your main thread ends...

can you provide the code you're running?

Huh...but if it's not the Background Workers what on earth could be keeping it from closing??? :?:

There's quite a bit of code...For now I'm just going to show what happens when it starts and then the background workers. Note that I combined 2 workers, so there's 4 now.

First Form. It runs when the program is started and asks for a password.

using System;
using System.Threading;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Text;

namespace WBB_CRT
{
    public partial class SecurityForm : Form
    {
        public SecurityForm()
        {
            InitializeComponent();
        }

        private string GetMD5Hash(string input)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] a_byte = Encoding.UTF8.GetBytes(input);

            a_byte = md5.ComputeHash(a_byte);
            System.Text.StringBuilder SB = new System.Text.StringBuilder();

            foreach (byte b in a_byte)
            {
                SB.Append(b.ToString("x2").ToLower());
            }

            return SB.ToString();
        }

        private void PasswordBox_TextChanged(object sender, EventArgs e)
        {
            if (GetMD5Hash(PasswordBox.Text) == //Specific MD5 Hash)
            {
                RightWrongImage.Image = Properties.Resources.Check_Mark;
                this.Refresh();

                Thread.Sleep(500);
                this.Hide();

                MainForm MainForm = new MainForm(); 
                MainForm.Show();   //Show the main program
            }
        }
    }
}

My MainForm initialization. All of my workers are on the main form

public MainForm()
        {
            InitializeComponent();
            
            //Irrelevant code

            UpdateProcessList.RunWorkerAsync();
            SetRunningBox.RunWorkerAsync();
            SetBlockedBox.RunWorkerAsync();
        }

Background worker 1

private void SetRunningBox_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                bool Running = false;

                foreach (Process process in Process.GetProcesses())
                {
                    if (process.ProcessName == ProcessController.BadProcess)
                    {
                        Running = true;

                        if (RunningBox.Checked == false)
                        {
                            RunningBox.Invoke(new ThreadStart(
                                delegate
                                {
                                    RunningBox.Checked = true;
                                    RemoveBtn.Enabled = false;
                                    StartBtn.Enabled = false;
                                }));
                        }
                    }
                }

                if (Running == false)
                {
                    if (RunningBox.Checked == true)
                    {
                        RunningBox.Invoke(new ThreadStart(
                            delegate
                            {
                                RunningBox.Checked = false;
                                RemoveBtn.Enabled = true;

                                if (BlockedBox.Checked == false)
                                {
                                    StartBtn.Enabled = true;
                                }
                            }));
                    }
                }

                if (SetRunningBox.CancellationPending)
                {
                    RunningBox.Invoke(new ThreadStart(
                        delegate
                        {
                            RunningBox.Checked = false;
                        }));
                    break;
                }
                Thread.Sleep(50);
            }
        }

Background worker 2

private void SetBlockedBox_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (ProcessController.BeingBlocked)
                {
                    if (BlockedBox.Checked == false)
                    {
                        BlockedBox.Invoke(new ThreadStart(
                            delegate
                            {
                                BlockedBox.Checked = true;
                            }));
                    }
                }

                else
                {
                    if (BlockedBox.Checked == true)
                    {
                        BlockedBox.Invoke(new ThreadStart(
                            delegate
                            {
                                BlockedBox.Checked = false;
                            }));
                    }
                }

                if (SetBlockedBox.CancellationPending)
                {
                    BlockedBox.Invoke(new ThreadStart(
                        delegate
                        {
                            BlockedBox.Checked = false;
                        }));
                    ProcessController.BeingBlocked = false;
                    break;
                }
                Thread.Sleep(50);
            }
        }

Background worker 3. Note that this one is started when I click a "Block" button. It prevents a program from starting.

private void BlockProcess_DoWork(object sender, DoWorkEventArgs e)
        {
            ProcessController.BeingBlocked = true;

            while (ProcessController.BeingBlocked == true)
            {
                foreach (Process process in Process.GetProcesses())
                {
                    if (process.ProcessName == ProcessController.BadProcess)
                    {
                        try
                        {
                            process.Kill();
                        }

                        catch
                        {
                        }
                    }
                }

                if (BlockProcess.CancellationPending)
                {
                    ProcessController.BeingBlocked = false;
                }

                Thread.Sleep(50);
            }
        }

And the last one

private void UpdateProcessList_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                try
                {
                    ProcessList.Invoke(new ThreadStart(
                        delegate
                        {
                            try
                            {
                                foreach (Process process in Process.GetProcesses())
                                {
                                    // It does not contain the name of a process that is running
                                    if (ProcessList.Items.Contains(process.ProcessName) == false)
                                    {
                                        ProcessList.Items.Add(process.ProcessName);
                                    }
                                }

                                foreach (Object ListedProcess in ProcessList.Items)
                                {
                                    // It contains the name of a process that is no longer running
                                    if (ReturnProcessInstance(Process.GetProcessesByName(ListedProcess.ToString())) == null)
                                    {
                                        if (ProcessList.SelectedIndex != 0)
                                        {
                                            ProcessList.SelectedIndex = 0;
                                        }

                                        else
                                        {
                                            ProcessList.SelectedIndex = 1;
                                        }

                                        ProcessList.Items.Remove(ListedProcess);
                                    }
                                }
                            }

                            catch (InvalidOperationException)
                            {
                                // In case one is updated while enumerating through the list. Still seems to update fine.
                            }
                        }));

                    Thread.Sleep(300);
                }

                catch
                {

                }
            }
        }

Not sure if anyone will want to read through all of that. ;)

Everyone else stumped, too? :'(

Background threads shouldn't stop your program from closing so there is something else going on. Have you tried using the VS multi-thread debugger to see what's going on?

I don't know how to use that but it looks like I figured it out. It looks like it was the way I showed the second form (my main part of the program). Instead of what I did above, I made a new thread that did Application.Run(new MainForm()); , started it from my password form, and then used this.Close() on my password form. Maybe it was staying alive because the password form was just hidden before?

Another weird problem now. I'm trying to open an OpenFileDialog on my second form but I'm getting a ThreadStateException. It says:

"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process."

Like it says, it works fine if I build it and run it outside of VS, but is it okay to just leave it with that exception?

Did you set STAThreadAttribute on your Main function? :)

Sure did. It still gives me that error. :confused:

Check the ThreadState and see what it is.

I don't know how to use that but it looks like I figured it out. It looks like it was the way I showed the second form (my main part of the program). Instead of what I did above, I made a new thread that did Application.Run(new MainForm()); , started it from my password form, and then used this.Close() on my password form. Maybe it was staying alive because the password form was just hidden before?

hey wildBamaBoy if I were you I'd be VERY careful! it sounds like you have issues going on that aren't being addressed properly. I'm not a threading expert but I do work with threads on a daily basis and they (threads) are unforgiving, lol! you REALLY do need to understand whats going on and how threads work before you start deploying them. For instance; like I was trying to explain to you earlier backGroundWorker threads are by default backGround threads and end once the main thread ends. you should do some debugging and find-out what's going on otherwise I PROMISE you other issue are waiting on you and they'll probably be a lot more difficult to identify so be CAREFUL, lol! but if there's anything I'm able to help/clarify with you I will. so take care and good luck!

Thank you for the advice and I agree they are very unforgiving.

Check the ThreadState and see what it is.

It says "Running"...

Maybe this is just a case of not doing it right. ;) Have I put [STAThread] in the right place? This is my first form which asks for a password, then closes and opens my main form in another thread.

using System;
using System.Threading;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Text;

namespace CRT
{
    public partial class SecurityForm : Form
    {
        public SecurityForm()
        {
            InitializeComponent();
        }

        [STAThread] //<--------------------------//
        static void MainFormThread()
        {
            Application.Run(new MainForm());
        }

        private string GetMD5Hash(string input)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] a_byte = Encoding.UTF8.GetBytes(input);

            a_byte = md5.ComputeHash(a_byte);
            System.Text.StringBuilder SB = new System.Text.StringBuilder();

            foreach (byte b in a_byte)
            {
                SB.Append(b.ToString("x2").ToLower());
            }

            return SB.ToString();
        }

        private void PasswordBox_TextChanged(object sender, EventArgs e)
        {
            if (GetMD5Hash(PasswordBox.Text) == //md5 hash)
            {
                RightWrongImage.Image = Properties.Resources.Check_Mark;
                this.Refresh();

                Thread.Sleep(500);

                Thread MainThread = new System.Threading.Thread(new System.Threading.ThreadStart(MainFormThread));
                MainThread.Start();

                this.Close();
            }
        }
    }
}

Try the full name [STAThreadAttribute]. And you probably need to take a look at your threading as suggested above.

Try the full name [STAThreadAttribute]. And you probably need to take a look at your threading as suggested above.

as Momerath said use/try [STAThreadAttribute] and as I suggested before be VERY careful! I think you really need to do some debugging. trust me, appearances can be deceiving when working with threads. what seems to be working on the surface may actually be a train wreck waiting to happen and it will be almost impossible to identify why it happened.

[STAThreadAttribute] doesn't do anything either.

Maybe it would be better to find a different way to open the second form...I'm not quite sure how to use the debugging tools or what I'm supposed to be looking for.

Finally got this to work. I found a different way to make it close completely without starting another thread that opens my main form.

I think I'll stay away from threads for now on. Very irritating! Thank you both.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.