// EMERGENT GAME TECHNOLOGIES PROPRIETARY INFORMATION // // This software is supplied under the terms of a license agreement or // nondisclosure agreement with Emergent Game Technologies and may not // be copied or disclosed except in accordance with the terms of that // agreement. // // Copyright (c) 1996-2007 Emergent Game Technologies. // All Rights Reserved. // // Emergent Game Technologies, Chapel Hill, North Carolina 27517 // http://www.emergent.net using System; using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Windows.Forms; using ThreadState = System.Threading.ThreadState; namespace Emergent.Gamebryo.SceneDesigner.GUI.Utility { /// /// Summary description for TimedInvoker. /// public class TimedInvoker { #region Private Data private Delegate m_callBack; private ISynchronizeInvoke m_invokableObject; private Thread m_thread; private TimeSpan m_interval; private TimeSpan m_timeOut; private bool m_bIsInvoking; private object m_lock; #endregion public TimedInvoker() { m_lock = new object(); m_bIsInvoking = false; m_timeOut = new TimeSpan(0, 0, 5);//default 5 second timeout } public Delegate CallBack { set { lock(m_lock) { m_callBack = value; } } } public ISynchronizeInvoke SychronizedObject { set { lock (m_lock) { m_invokableObject = value; } } } public TimeSpan Interval { set { lock (m_lock) { m_interval = value; } } } public TimeSpan TimeOut { set { m_timeOut = value; } } public bool IsRunning { get { lock(m_lock) { return (m_thread.ThreadState & ThreadState.Running) == ThreadState.Running; } } } public bool IsInvoking { get { lock(m_lock) { return m_bIsInvoking; } } } public void Start() { lock (m_lock) { m_thread = new Thread(new ThreadStart(Run)); } m_thread.Start(); } public void Stop() { m_thread.Interrupt(); if (!m_thread.Join(1000)) { m_thread.Abort(); Console.WriteLine("Forcibly terminating thread"); } } /// /// /// /// /// Control.Invoke has a known bug in Dot Net 1.1 sp1 /// where it will hang(race condition) under stress. /// BeginInvoke is used instead, with a timeout value /// private void Run() { try { while (true) { //lock not needed for a sychronous Invoke //Note: this means that all of the other lock calls are //probably unnesseary too, but I'll keep them in place //since they may come in handy if we need to do //asyncronous calls, and their relative overhead is //minimal //lock (m_lock) //{ m_bIsInvoking = true; IAsyncResult result = m_invokableObject.BeginInvoke( m_callBack, new object[] {null, null}); WaitHandle waitHandle = result.AsyncWaitHandle; if (waitHandle.WaitOne(m_timeOut, true)) { m_invokableObject.EndInvoke(result); } else { Debug.WriteLine( "Delegate Object appears to be hung"); } m_bIsInvoking = false; //} Thread.Sleep(m_interval); } } catch (ThreadInterruptedException) { return; } catch (Exception e) { MessageBox.Show(e.ToString(), "Exception thrown in timer code"); } } } }