I never worker too much with timers and delays, so I’m pretty sure I’m doing something really really ugly with my code but I can’t figure out a solution.
Ok… I have a class called AnimatorsPool, which contains and handles a lot of Animator classes at once. Animator is just a simple, timer based, control mover.
public sealed class AnimatorsPool : IDisposable
{
private Boolean m_Disposed;
private Boolean m_Stopped;
private Boolean m_Waiting;
private Int32 m_DelayBetween;
private Int32 m_DelayStart;
private List<Animator> m_Animators;
private Stopwatch m_Stopwatch;
public Boolean AnimationsFinished
{
get
{
foreach (Animator animator in m_Animators)
{
if (!animator.AnimationFinished)
return false;
}
return true;
}
}
public AnimatorsPool(Int32 delayBetween, Int32 delayStart)
{
m_Disposed = false;
m_Stopped = false;
m_Waiting = false;
m_DelayBetween = ((delayBetween < 0) ? 0 : delayBetween);
m_DelayStart = ((delayStart < 0) ? 0 : delayStart);
m_Animators = new List<Animator>();
}
private void Wait(Int32 delay)
{
m_Stopwatch = Stopwatch.StartNew();
m_Waiting = true;
while (!m_Stopped && (m_Stopwatch.ElapsedMilliseconds <= delay))
Application.DoEvents();
m_Waiting = false;
m_Stopwatch.Stop();
}
public void Add(Animator animator)
{
m_Animators.Add(animator);
}
public void Dispose()
{
if (!m_Disposed)
{
foreach (Animator animator in m_Animators)
animator.Dispose();
m_Animators.Clear();
m_Animators = null;
m_Disposed = true;
}
GC.SuppressFinalize(this);
}
public void Start()
{
if (m_Animators.Count > 0)
{
if (m_DelayStart > 0)
Wait(m_DelayStart);
m_Animators[0].Start();
if (m_Animators.Count > 1)
{
for (Int32 i = 1, length = m_Animators.Count; i < length; ++i)
{
if (m_DelayBetween > 0)
Wait(m_DelayBetween);
m_Animators[i].Start();
}
}
}
}
public void Stop()
{
m_Stopped = true;
while (m_Waiting)
Application.DoEvents();
}
}
Inside my main form, which is sometimes using AnimatorsPool, I use the following code:
using (AnimatorsPool pool = new AnimatorsPool(100, (delayAction ? 100 : 0)))
{
m_AnimatorsPools.Add(pool);
for (Int32 i = (controlsCount - 1); i >= 0; --i)
{
Animator animator = new Animator(controls[i], coordinates[i], 50);
pool.Add(animator);
}
pool.Start();
while (!pool.AnimationsFinished)
Application.DoEvents();
m_AnimatorsPools.Remove(pool);
}
Ok now… what happened in the beginning was that, if I exited the program while AnimatorsPool was still running Wait() method, my main form was disappearing but the process was still running undefinately in my task manager because of that.
So I implemented a Dispose override in my main form:
protected override void Dispose(Boolean disposing)
{
if (!m_Disposed)
{
if (disposing)
{
s_RandomProvider.Dispose();
foreach (AnimatorsPool pool in m_AnimatorsPools)
pool.Dispose();
m_AnimatorsPools.Clear();
m_AnimatorsPools = null;
}
m_Disposed = true;
}
base.Dispose(disposing);
}
Ok… now my program exits properly sometimes, but sometimes not. And what I can see from debug is that, when it happens, it’s because some AnimatorsPool is still running the Wait() method even if m_Stopped is set to true.
I think I should use threads, timers or something like that, but I’ve no experience. Any help is welcome! Thanks!
Whatever you do, don’t do this:
You should use timers and event-driven for this, instead of busy-waiting. That is only ever OK in embedded real-time stuff.
You need to rewrite your code pretty much, and it is difficult to give you pointers without creating a lesson in timers and event-driven development.
EDIT: From the
Application.DoEventsdocumentation in MSDN (emphasis mine):