Hi,
I appologize in advance for my limited threading knowledge. I've
programmed quite a bit, but never used threads before. I know the
general idea behind them though and I've read most of the Threading
documentation in the MSDN library. But if I have the wrong programming
model in my head, by all means correct me.
My application is this (I'm using C#.NET), I have hardware that
timestamps signals coming into it and a digital IO card to continually
grab the data from the hardware. I want to create a background thread
to do this data collection continuously in the background. The reason I
want it continuous is that the hardware (basically a counter)
eventually rolls over, so my software keeps track of this rollover so
that all the signals coming in have the correct absolute time. So I
want this data collection to be going on continuously in the
background. Sounds like a perfect thing for threads. Now I've defined a
callback for the class that runs in this background thread, I'm
basically going to make it call back into my main program after a
certain period of time, or when a certain amount of data is collected
and copy that data to an array of doubles in the main program. This
array will be overwritten each time the callback gets called. That's
fine, the absolute timing information will taken care of, but my main
program will be able to choose when to use the data, unused data will
get overwritten and lost which is fine (the important thing is that the
absolute timing information is always correct).
So first thing, I want the method that's called in the thread to
basically just enter a while loop collecting data until the main
program tells it to stop. So I define a _taskRunning variable and set
it to true when I start the measurement loop, it keeps going until this
changes. So now I define another method in my ThreadClass that sets
this to false to stop the measurement. I've tried it out and it works,
the measurement thread maybe keeps going through the loop once more,
but it quits when I update the _taskRunning bool. Now is this the
proper way to do it, or have I just broken a bunch of proper coding
rules If I have, what's the correct way to do it Remember, I want to
start this background thread running to collect measurement data,
periodically have it callback to the main program and update an array
variable there, run indefinitely in the background until the user
clicks stop in the main program. How do I communicate the stop action
to the background thread
Second question, in that callback that updates the data array in the
main program, I know I have to worry about the main program and the
Thread working with that variable at the same time. Is this where I'm
supposed to use the Monitor class And if so how do I go about using it
Thanks for any help you can offer,
Chris Erven
PS. Since I know this post might be a bit convoluted, here's the pertinent code fragments
// Main Program Class
// Start the Channel Counts Measurement
private void StartMeasurement()
{
// Setup NI
objects, happens in the Measurement object, pass the required input to
// the Measurement Thread object
_measureThreadWorker = new MeasurementThread(_physicalChannel,
_clockFreq,
_numSamples, _timeout, _timeTagRes,
_baseFileName, new
MeasurementThreadCallback(DataUpdateCallback));
// Set the MeasurementThread to running
_measureThreadWorker.StartTask();
// Create a thread to execute the task, and then start the thread
_measureThread
= new Thread(new
ThreadStart(_measureThreadWorker.Measurement));
_measureThread.Start();
MessageBox.Show("ChannelRatesUtilityForm.StartMeasurement measureThread
started");
}
// Stop the Channel Counts Measurement
private void StopMeasurement()
{
MessageBox.Show("ChannelRatesUtilityForm.StopMeasurement");
// Stop the measurement thread Thread.Join();
_measureThreadWorker.StopTask();
_measureThread.Join();
MessageBox.Show("ChannelRatesUtilityForm.StartMeasurement measureThread
ended, main thread ends.");
}
// Callback method from the measurement thread every time a block of data is filled
// The callback method must match the signature of the callback delegate
public static void DataUpdateCallback(int count)
{
MessageBox.Show("DataUpdateCallback " + count);
}
// Thread Worker Class
public void Measurement()
{
_taskRunning = true;
int i = 0;
while (_taskRunning)
{
if (_measureCallback != null)
{
Thread.Sleep(3000);
_measureCallback(i);
i++;
}
}
}
// Start the Measurement task
public void StartTask()
{
MessageBox.Show("MeasurementThread.StartTask");
_taskRunning = true;
}
// Stop the Measurement task
public void StopTask()
{
MessageBox.Show("MeasurementThread.StopTask");
_taskRunning = false;
}

How to Stop Background Thread that's looping?
Dave Salzman
I have a similar situation...Maybe someone can let me know if this seems reasonable or maybe there is a better way to do this
I have a little application that communicates with a camera that might need to wait up to 5-10 seconds trying to capture an image because another application might still have the camera open....I don't want to get into that...but anyways...
I start up a background worker that just keeps banging away at the camera until it either gets the picture, or a certain amount of time elapses. The way I am handling the timeout is that before I start the background worker, I start a timer on the form/main thread that waits for a predetermined amount of time.
Once that timespan has elapsed, I do something like this:
If picWorker.isBusy Then
picTimer.Stop()
picWorker.cancelAsync()
End If
In my main DoWork loop, I just keep checking to see if the image is nothing and the CancellationPending is false.
I have a try..except structure in the loop that tries to take a picture. It just swallows the exception if it can't take a picture. I then just handle the exception of not being able to take the picture once my timeout has fired.
tony_qy
You seem to be on the right track with everything. Here are some suggestions that may solve your problem:
First, move all the code for starting and stopping the thread to the MeasurementThread class. It is easier to manage the whole thread process if the class is self-contained.
Second, change the Thread.Join() call to use a timeout value, so it does not block indefinitely.
Third, add an Abort() method to the class which calls Thread.Abort(), in case setting the flag value does not achieve the desired result.
Fourth, modify the Thread.Sleep(3000) call to a value far less in order to allow the thread to be more responsive to the change in the execution flag.
Finally, make sure the variable access is thread-safe - see the lock keyword and the ReaderWriterLock class.
Here is an example of what I am talking about:
public class MeasurementThread
{
private Thread _Thread;
private ThreadStart _FunctionPointer;
private bool _taskRunning;
private MeasurementThreadCallback _callBackPointer;
private ReaderWriterLock _Lock;
... any other variables here...
public MeasurementThread(... parameters ...)
{
_Lock = new ReaderWriterLock();
_FunctionPointer = new ThreadStart(Measurement);
... any other construction here ...
}
//Property to tell if the thread is running.
public bool IsExecuting
{
get
{
bool returnValue = false; //Return value.
lock(this)
{
_Lock.AcquireReaderLock(10000);
returnValue = _Thread.IsAlive;
_Lock.ReleaseLock();
}
return returnValue;
}
}
//Begins the thread execution.
public void StartTask()
{
MessageBox.Show("MeasurementThread.StartTask");
_taskRunning = true;
//Create and launch thread.
_Thread = new Thread(_FunctionPointer);
_Thread.IsBackground = true;
_Thread.Start();
}
//Ends the thread execution - one way or another
public void StopTask()
{
MessageBox.Show("MeasurementThread.StartTask");
if (_Thread != null)
{
_taskRunning = false;
_Thread.Join(12000);
if (_Thread.IsAlive)
Abort();
_Thread = null;
}
_taskRunning = false;
}
//Forces the thread to terminate.
public void Abort()
{
if (_Thread != null)
{
_Thread.Abort();
}
_Thread = null;
}
public void Measurement()
{
_taskRunning = true;
int i = 0;
while (_taskRunning)
{
if (_measureCallback != null)
{
Thread.Sleep(500);
lock(this)
{
//If an error occurs in the callback method
//implementation and is not caught, the thread will
// be terminated abruptly.
try
{
_measureCallback(i);
}
catch (Exception)
{
}
}
i++;
}
}
}
}
--
Sam Jones
Adaptive Intelligence
http://www.adaptiveintelligence.net