none
一个timer是否可以看作一个thread? RRS feed

  • 问题

  • 进一步:

    一个timer里运行一个thread需要注意些什么? \

    3q


    我喜欢淡淡的生活,静悄悄地做我喜欢做的事,不要留下什么印痕,也不想被人瞩目。

    2013年4月15日 6:34

答案

  • 一个Timer可以看成是一个Thread,可以理解成一个死循环的Thread(触发事件的死循环Thread),除非你禁用Timer。

    一个Timer里运行Thread,因为Timer本身每隔一定时间(单位:毫秒)会自动触发Tick事件,因此小心产生多个实例。

    以上说的是WinForm开发中那个System.Windows.Forms中的Timer。另外还有System.Threading.Timer和System.Timers.Timer.

    源代码(Sytem.Windows.Forms.Timer):

    [DefaultEvent("Tick"), SRDescription("DescriptionTimer"), DefaultProperty("Interval"), ToolboxItemFilter("System.Windows.Forms")]
    public class Timer : Component
    {
        // Fields
        private bool enabled;
        private int interval;
        private object syncObj;
        private GCHandle timerRoot;
        private TimerNativeWindow timerWindow;
        private object userData;
    
        // Events
        [SRDescription("TimerTimerDescr"), SRCategory("CatBehavior")]
        public event EventHandler Tick;
    
        // Methods
        public Timer()
        {
            this.syncObj = new object();
            this.interval = 100;
        }
    
        public Timer(IContainer container) : this()
        {
            container.Add(this);
        }
    
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.timerWindow != null)
                {
                    this.timerWindow.StopTimer();
                }
                this.Enabled = false;
            }
            this.timerWindow = null;
            base.Dispose(disposing);
        }
    
        protected virtual void OnTick(EventArgs e)
        {
            if (this.onTimer != null)
            {
                this.onTimer(this, e);
            }
        }
    
        public void Start()
        {
            this.Enabled = true;
        }
    
        public void Stop()
        {
            this.Enabled = false;
        }
    
        public override string ToString()
        {
            return (base.ToString() + ", Interval: " + this.Interval.ToString(CultureInfo.CurrentCulture));
        }
    
        // Properties
        [DefaultValue(false), SRCategory("CatBehavior"), SRDescription("TimerEnabledDescr")]
        public virtual bool Enabled
        {
            get
            {
                if (this.timerWindow == null)
                {
                    return this.enabled;
                }
                return this.timerWindow.IsTimerRunning;
            }
            set
            {
                lock (this.syncObj)
                {
                    if (this.enabled != value)
                    {
                        this.enabled = value;
                        if (!base.DesignMode)
                        {
                            if (value)
                            {
                                if (this.timerWindow == null)
                                {
                                    this.timerWindow = new TimerNativeWindow(this);
                                }
                                this.timerRoot = GCHandle.Alloc(this);
                                this.timerWindow.StartTimer(this.interval);
                            }
                            else
                            {
                                if (this.timerWindow != null)
                                {
                                    this.timerWindow.StopTimer();
                                }
                                if (this.timerRoot.IsAllocated)
                                {
                                    this.timerRoot.Free();
                                }
                            }
                        }
                    }
                }
            }
        }
    
        [DefaultValue(100), SRDescription("TimerIntervalDescr"), SRCategory("CatBehavior")]
        public int Interval
        {
            get
            {
                return this.interval;
            }
            set
            {
                lock (this.syncObj)
                {
                    if (value < 1)
                    {
                        object[] args = new object[] { value, 0.ToString(CultureInfo.CurrentCulture) };
                        throw new ArgumentOutOfRangeException("Interval", SR.GetString("TimerInvalidInterval", args));
                    }
                    if (this.interval != value)
                    {
                        this.interval = value;
                        if ((this.Enabled && !base.DesignMode) && (this.timerWindow != null))
                        {
                            this.timerWindow.RestartTimer(value);
                        }
                    }
                }
            }
        }
    
        [SRCategory("CatData"), Localizable(false), Bindable(true), DefaultValue((string) null), TypeConverter(typeof(StringConverter)), SRDescription("ControlTagDescr")]
        public object Tag
        {
            get
            {
                return this.userData;
            }
            set
            {
                this.userData = value;
            }
        }
    
        // Nested Types
        private class TimerNativeWindow : NativeWindow
        {
            // Fields
            private Timer _owner;
            private bool _stoppingTimer;
            private int _timerID;
            private static int TimerID = 1;
    
            // Methods
            internal TimerNativeWindow(Timer owner)
            {
                this._owner = owner;
            }
    
            public override void DestroyHandle()
            {
                this.StopTimer(false, IntPtr.Zero);
                base.DestroyHandle();
            }
    
            private bool EnsureHandle()
            {
                if (base.Handle == IntPtr.Zero)
                {
                    CreateParams cp = new CreateParams {
                        Style = 0,
                        ExStyle = 0,
                        ClassStyle = 0,
                        Caption = base.GetType().Name
                    };
                    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                    {
                        cp.Parent = (IntPtr) NativeMethods.HWND_MESSAGE;
                    }
                    this.CreateHandle(cp);
                }
                return (base.Handle != IntPtr.Zero);
            }
    
            ~TimerNativeWindow()
            {
                this.StopTimer();
            }
    
            private bool GetInvokeRequired(IntPtr hWnd)
            {
                if (hWnd != IntPtr.Zero)
                {
                    int num;
                    int windowThreadProcessId = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, hWnd), out num);
                    int currentThreadId = SafeNativeMethods.GetCurrentThreadId();
                    return (windowThreadProcessId != currentThreadId);
                }
                return false;
            }
    
            protected override void OnThreadException(Exception e)
            {
                Application.OnThreadException(e);
            }
    
            public override void ReleaseHandle()
            {
                this.StopTimer(false, IntPtr.Zero);
                base.ReleaseHandle();
            }
    
            public void RestartTimer(int newInterval)
            {
                this.StopTimer(false, IntPtr.Zero);
                this.StartTimer(newInterval);
            }
    
            public void StartTimer(int interval)
            {
                if (((this._timerID == 0) && !this._stoppingTimer) && this.EnsureHandle())
                {
                    this._timerID = (int) SafeNativeMethods.SetTimer(new HandleRef(this, base.Handle), TimerID++, interval, IntPtr.Zero);
                }
            }
    
            public void StopTimer()
            {
                this.StopTimer(true, IntPtr.Zero);
            }
    
            public void StopTimer(bool destroyHwnd, IntPtr hWnd)
            {
                if (hWnd == IntPtr.Zero)
                {
                    hWnd = base.Handle;
                }
                if (this.GetInvokeRequired(hWnd))
                {
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, hWnd), 0x10, 0, 0);
                }
                else
                {
                    lock (this)
                    {
                        if ((!this._stoppingTimer && (hWnd != IntPtr.Zero)) && UnsafeNativeMethods.IsWindow(new HandleRef(this, hWnd)))
                        {
                            if (this._timerID != 0)
                            {
                                try
                                {
                                    this._stoppingTimer = true;
                                    SafeNativeMethods.KillTimer(new HandleRef(this, hWnd), this._timerID);
                                }
                                finally
                                {
                                    this._timerID = 0;
                                    this._stoppingTimer = false;
                                }
                            }
                            if (destroyHwnd)
                            {
                                base.DestroyHandle();
                            }
                        }
                    }
                }
            }
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == 0x113)
                {
                    if (((int) m.WParam) == this._timerID)
                    {
                        this._owner.OnTick(EventArgs.Empty);
                        return;
                    }
                }
                else if (m.Msg == 0x10)
                {
                    this.StopTimer(true, m.HWnd);
                    return;
                }
                base.WndProc(ref m);
            }
    
            // Properties
            public bool IsTimerRunning
            {
                get
                {
                    return ((this._timerID != 0) && (base.Handle != IntPtr.Zero));
                }
            }
        }
    }

    如果你想要精确计时,并且长时间计时(比如使用服务器制作Windows Service等),需要使用System.Timers.Timer类)。

    至于System.Thread.Timer类是一个由ThreadPool制作的类。它实现了IDispose接口,意味着你啥时候不用就可以调用把这个类回收。

    System.Windows.Forms中的Timer是图形化的,计时并不精确。


    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    2013年4月15日 7:59
    版主