Ensuring that it is safe to exit

M

Mike

Greetings,

We have a synchronization scenario where we would like to ensure that
it is safe to exit the main application before actually exiting.

The scenario consists of one or more timers (or threads) that are
running that are in mid-stream doing their assigned tasks, such as, for
example, saving to an XML file.

Periodically, when exiting our XML output is corrupted, the save was
incomplete. So the next time into the application, we have what is in
effect an invalid format, even though it was one (or more) of the
records that failed to write.

So, we would like to give these timers (or threads) an opportunity to
finish what they are doing and signal to the application that it is
safe.

We've been thinking about the problem. Semaphores looked like a
potentially promising synchronization object, for example, a count
associated with the timers running. However, there does not appear to
be a means of querying a Semaphore for current or available count, so
probably not the greatest fit for the problem at hand.

Perhaps also Mutex. One mutex per timed event and if the application
detects that any of the mutexes are consumed, then it is not safe to
exit.

The opposite end of that relationship, of course, is the application to
somehow signal its intention to exit in order for the timers (or
threads) to not fire up again.

Anyways, this is the thought process. How feasible is this, has anyone
done it, etc, etc? Thanks in advance.

Best regards,
Michael
 
M

Markus Stoeger

Mike said:
We've been thinking about the problem. Semaphores looked like a
potentially promising synchronization object, for example, a count
associated with the timers running. However, there does not appear to
be a means of querying a Semaphore for current or available count, so
probably not the greatest fit for the problem at hand.

Why not use a simple "static int counter" variable? Increase the counter
every time you start a timer, and decrease it when a timer is done.
You'll either have to make that thing volatile or use lock() to be able
to safely access the variable from different threads.
As long as the counter is >0, you cannot exit the application yet.

You could also save all the timers in some list (don't forget to lock()
it), and check timerList.Count for >0. This way it should be possible to
gracefully interrupt running timers when the user wants to exit.

hope that helps. If not, please provide more details!
Max
 
K

Kevin Spencer

Hi Michael,

We have a number of Windows Services that all use the same base class, which
is not a Service, but a business class designed to run in a Service. The
class has public methods for starting, pausing, and stopping. But the actual
work is done in a thread. We can actually run any number of these in a
single Windows Service (and do in some cases). Each instance manages itself.
The core of it is in the way the "Run" thread is handled. Here is an example
of the Start and Stop methods:

public void Start()
{
try
{
// Create and start the RunTimer
if (_RunTimer != null) return; // Not Stopped
RaiseStarting(new EventArgs());
_RunTimer = new System.Timers.Timer();
_RunTimer.Interval = _RunTimerInterval;
_RunTimer.AutoReset = true;
_RunTimer.Elapsed += new ElapsedEventHandler(_RunTimer_Elapsed);
_RunTimer.Start();
_State = ServiceState.Started;
// Start the "Run" thread
RunThread = new Thread(new ThreadStart(Run));
RunThread.Name = _AppName + " Run Thread";
RunThread.Start();
RaiseStarted(new EventArgs());
}
catch (Exception ex)
{
HandleError(ex, false, "ServiceClass.Start()");
throw;
}
}

public void Stop(bool waitOnThread)
{
try
{
if (_RunTimer == null) return; // Not started
RaiseStopping(new EventArgs());
_State = ServiceState.Stopping;
if (waitOnThread)
{
if (RunThread != null)
RunThread.Join(TimeSpan.FromMinutes(5D));
}
_RunTimer.Stop();
_RunTimer.Dispose();
_RunTimer = null;
RaiseStopped(new EventArgs());
_State = ServiceState.Stopped;
}
catch (Exception ex)
{
_State = ServiceState.Errors;
HandleError(ex, false, "ServiceClass.Stop()");
throw;
}
}

As you can see, the mechanism for preventing an abnormal termination is
simply to Join the thread after singalling it. The thread monitors the
_State field, and halts itself gracefully when it is set to Stopping.

--
HTH,

Kevin Spencer
Microsoft MVP
Chicken Salad Surgery

Accept the Unexpected.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top