David Pollard David Pollard - 6 days ago 6
C# Question

c# How to check a thread is finished before starting another one

This is the first time I have tried to use threads in an application.
I know this question has been asked before but of the solutions I have looked at I can't see how to apply them in my situation.

I have a program where a datagridview is refreshed on a timer every 60 seconds. The data comes from a SQL database. This timer also starts a worker thread to look for a particular Bluetooth device and update the database based on its findings in the background. The Bluetooth lookup is particularly slow which is why I put it in a worker thread.

My problem is, sometimes a new worker thread starts before the previous one has finished. At least that is the only logical explanation for the errors I'm getting. The big give away is a file locked error when the only thing that can be locking the file is another worker thread from the same application.

Here is the code I'm using to start the background thread.

private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

// If the user is not on a Remote desktop connection
if (!remoteDesktopUser)
{

// Run the Bluetooth Search in a worker thread
Thread thread = new Thread(new ThreadStart(this.checkProximity));
thread.IsBackground = true;
thread.Start();
}

// Load User Data from the DB and display on the screen
loadUserData();
}


It would seem that the solution is to use thread.IsAlive() but I haven't been able to find a good example. It seems odd to try and check for the existence of a thread when I have just created a new one with "Thread thread = new Thread()"

Obviously I'm missing something. I'm using Visual Studio 2008.
Thanks for any ideas
David

UPDATE

Based on the proposed solution by krw12572 below I tried this...

I changed the != to == because I still want to run the loadUserData() method in the primary thread every time through.

In the editor I get a green underline on "_bluetoothSearchThread" telling me the field is never assigned and will always have the value NULL.

At run time I get an "Object Reference Not Set to An instance of an object" error on this line.

if (_bluetoothSearchThread == null && _bluetoothSearchThread.IsAlive)


How does this value get assigned?

private Thread _bluetoothSearchThread;
private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

// Check if Worker Thread is already running.
if (_bluetoothSearchThread == null && _bluetoothSearchThread.IsAlive)
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running");

// If the user is not on a Remote desktop connection
if (!remoteDesktopUser)
{
// Check if the users mobile phone is within range
// Run the Bluetooth Search in a worker thread

Thread thread = new Thread(new ThreadStart(this.checkProximity));
thread.IsBackground = true;
thread.Start();
}
}
else
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Worker Thread still running don't start another one");
}

// Load User Data from the DB and display on the screen
loadUserData();
}


Update 2

OK I think I have figured it out.
I changed the != Null back to the way it was and turned the IF and Else Around the other way.

Then I had to use my brain a bit and changed "thread" to "_bluetoothSearchThread"

Now the code compiles and runs. Now I just need to test it by triggering the conditions that cause the file lock error to see if I have actually fixed the original problem. If it works I'll mark krw12572 answer as correct.

Update 2.5
I also had to move this line so it doesn't create a new instance too soon

_bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));


So this is the working solution.

private Thread _bluetoothSearchThread;
private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");


// Check if Worker Thread is already running.
if (_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive)
{
// Thread is still running. Just log it and move on.
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "******** Worker Thread still running don't start another one *********");
}
else
{
if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running");

// If the user is not on a Remote desktop connection
if (!remoteDesktopUser)
{
// Check if the users mobile phone is within range
// Run the Bluetooth Search in a worker thread
_bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));
_bluetoothSearchThread.IsBackground = true;
_bluetoothSearchThread.Start();
}
}

// Load User Data from the DB and display on the screen
loadUserData();
}

Answer

If you want only one thread running at a time, then you can create a field to store Thread instance. Using that thread instance you can check if it's already running or not by using _threadInstance.IsAlive.

private Thread _bluetoothSearchThread;
private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
    if(_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive) 
        return;        //It means one thread is already performing the search operation.

    if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

    // If the user is not on a Remote desktop connection
    if (!remoteDesktopUser)
    {

        // Run the Bluetooth Search in a worker thread
        _bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));
        _bluetoothSearchThread.IsBackground = true;
        _bluetoothSearchThread.Start();
    }

    // Load User Data from the DB and display on the screen
    loadUserData();
}