Search code examples
c#multithreadingbackgroundworker

Background worker freezes / dies while running


This may be a hardware issue, as I'm not exactly sure how background workers are implemented, but here is the issue: I have 3 background workers running different threads. I've coded those threads to display when they start and end, and I am getting some very strange results.

On some executions, all 3 threads will start, but only 1 will end (and I've waited many minutes to see if the program was just executing very slow, and put breaks in the code - it's not running slow, the background worker just "dies"). Other executions I get 2 threads to finish. Other times I get only 2 threads starting, and both end, etc.

I am not changing the code (entered below) at all between runs, I am simply stopping the program and restarting it. As such, I suspect it may be a hardware issue (CPU maybe?). Unfortunately, I don't have another PC to test the program on right now, and the PC that I am using is ... "far from the best".

So, my question: Could there be hardware issues that cause a background worker (and the thread that it is working on) to just die off / not start at all? Or does it absolutely have to be something in the code?

(The following is obviously not really my code. It is a much simpler version that illustrates the problem) Code:

public partial class Form1 : Form
{
    BackgroundWorker[] workers = new BackgroundWorker[3];
    Stopwatch timeKeeper = new Stopwatch();
    string text = "";

    public Form1()
    {
        timeKeeper.Start();

        InitializeComponent();

        for (int i = 0; i < 3; i++)
        {
            workers[i] = new BackgroundWorker();
            workers[i].DoWork += new System.ComponentModel.DoWorkEventHandler(this.BWWorker_DoWork);
            workers[i].RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.BWWorker_WorkDone);
            workers[i].RunWorkerAsync(i);
        }
    }

    private void BWWorker_WorkDone(object sender, RunWorkerCompletedEventArgs e)
    {
        this.textBox1.Text = text;
    }

    private void BWWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        switch (e.Argument.ToString())
        {
            case "0":
                startThread1();
                break;

            case "1":
                startThread2();
                break;

            case "2":
                startThread3();
                break;
        }
    }

    void startThread1()
    {
        text += Environment.NewLine + "Starting thread 1" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();

        this.textBox1.Text = text;

        for (int i = 0; i < 25000; i++)
        {

        }

        text += Environment.NewLine + "Ending thread 1" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();
    }

    void startThread2()
    {
        text += Environment.NewLine + "Starting thread 2" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();

        this.textBox1.Text = text;

        for (int i = 0; i < 10000; i++)
        {

        }

        text += Environment.NewLine + "Ending thread 2" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();
    }

    void startThread3()
    {
        text += Environment.NewLine + "Starting thread 3" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();

        this.textBox1.Text = text;

        for (int i = 0; i < 75000; i++)
        {

        }

        text += Environment.NewLine + "Ending thread 3" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();
    }
}

The result on 3 back-to-back runs with no code changes is as follows : (The 3rd pic runs all 3, as desired. The first 2 run/finish some of the threads, but not all (again, I've let the program run for minutes, so I know it's not just running slow) ... ?)

enter image description here


Solution

  • So, my question: Could there be hardware issues that cause a background worker (and the thread that it is working on) to just die off / not start at all? Or does it absolutely have to be something in the code?

    That is very, very unlikely.

    I suspect the real issue is that you are updating text from multiple theads. Concatenating strings like this is not a thread-safe operation, and the threads can be expected to complete at about the same time. Even though the loops have a different number of iterations, minor fluctuations in thread scheduling can cause them to step on each other. In particular, the line

    text += Environment.NewLine + "Ending thread 1" + Environment.NewLine + "at " + timeKeeper.Elapsed.ToString();
    

    could run such that

    • Thread 1 reads the current value of text.
    • Thread 1 is interrupted
    • Thread 2 is scheduled and also reads the current value of text
    • Thread 2 updates the value in text
    • Thread 2 is interrupted
    • Thread 1 is scheduled. It overwrites text, without re-reading the change just made by Thread 2.

    Try using lock statements around changes to resources shared by the threads.