private bool _isExiting;
private bool IsExiting //if this is set to true exit but wait for all threads
{
get { return _isExiting; }
set
{
_isExiting = value;
if (value)
Stop();
}
}
private JobProfiler profiler;
protected override void OnStart(string[] args)
{
try
{
profiler = new Profiler(MaxThreads);
ThreadPool.QueueUserWorkItem(DoWork); // main thread set up thread for work
}
catch (Exception ex)
{
LogError(ex);
Stop();
}
}
protected void DoWork(object data)
{
while (!IsExiting)
{
try
{
profiler.RunProfiles(profiles); //this should wait until all child threads are done
Thread.Sleep(ThreadSleep); //sleep before next iteration
}
catch (Exception ex)
{
LogError(ex);
errorCount++;
if (errorCount > 10) //if 10 serious errors happen stop the service
{
IsExiting = true;
break;
}
}
}
}
protected override void OnStop()
{
try
{
if(profiler != null)
profiler.IsExiting = true; //setting a variable here to signal all remaining threads to stop
//here it should be waiting for the main and child threads to finish
base.OnStop();
}
catch
{
base.OnStop();
}
}
//profiler class
//******************************************************
private readonly Semaphore _throttle; //setting up a throttle for the number of threads we will allow to execute at once
public void RunProfiles(List<Profiles> profiles)
{
foreach (var profile in profiles)
{
if (IsExiting) break; //if an exit command is called stop iterating
_throttle.WaitOne(); // Wait on a semaphore slot to become available
ThreadPool.QueueUserWorkItem(RunProfile, profile ); //then add to thread queue
}
}
private void RunProfile(object profile)
{
try
{
var p = (profile as Profile);
if (p == null || IsExiting)
{
_throttle.Release(); // Release the semaphore slot if profile not found or if we're exiting
return;
}
//****
//do a bunch of stuff
//****
_throttle.Release(); // Release the semaphore slot
}
catch (Exception ex)
{
log.Error(ex);
_throttle.Release(); // Release the semaphore slot
}
}