Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用计时器处理类的正确方法是什么?_C#_.net_Vb.net_Timer - Fatal编程技术网

C# 使用计时器处理类的正确方法是什么?

C# 使用计时器处理类的正确方法是什么?,c#,.net,vb.net,timer,C#,.net,Vb.net,Timer,假设我有一个类,它有一个计时器对象,它不做任何重要的工作——只是一些GUI工作。假设有两种情况,计时器每5分钟消失一次: 在Timer\u expressed委托中,有许多工作要做,需要2分钟才能完成 在Timer\u expressed委托中,几乎没有要做的工作,需要几毫秒才能完成 处理对象和计时器的正确方法是什么?事件委托运行的计时器\u经过的时间长度是否会影响您关于如何正确处置的决定 对此有多种方法,正如Alex在评论中所说,这取决于代理将使用的对象是否也被处理 假设我们有一个“最坏情况”

假设我有一个类,它有一个计时器对象,它不做任何重要的工作——只是一些GUI工作。假设有两种情况,计时器每5分钟消失一次:

  • Timer\u expressed
    委托中,有许多工作要做,需要2分钟才能完成
  • Timer\u expressed
    委托中,几乎没有要做的工作,需要几毫秒才能完成

  • 处理对象和计时器的正确方法是什么?事件委托运行的
    计时器\u经过的时间长度是否会影响您关于如何正确处置的决定

    对此有多种方法,正如Alex在评论中所说,这取决于代理将使用的对象是否也被处理

    假设我们有一个“最坏情况”场景,在该场景中,代理确实需要使用将被处置的对象。
    处理此问题的一个好方法类似于
    进程
    对象的方法:
    WaitForExit()
    。此方法将简单地循环,直到看到代理完成工作(在代理运行之前和之后设置
    working
    bool),然后返回。现在,您可以在使用该类的代码中使用类似的内容:

    // Time to shut down
    myDisposable.WaitForFinish();
    myDisposable.Dispose();
    

    因此,我们基本上是在处理委托之前确保委托已完成,停止任何类型的
    ObjectDisposedException

    这有多种方法,正如Alex在评论中所说,这取决于委托将使用的对象是否也被处理

    假设我们有一个“最坏情况”场景,在该场景中,代理确实需要使用将被处置的对象。
    处理此问题的一个好方法类似于
    进程
    对象的方法:
    WaitForExit()
    。此方法将简单地循环,直到看到代理完成工作(在代理运行之前和之后设置
    working
    bool),然后返回。现在,您可以在使用该类的代码中使用类似的内容:

    // Time to shut down
    myDisposable.WaitForFinish();
    myDisposable.Dispose();
    

    因此,我们基本上是在处理委托之前确保委托完成,停止任何类型的
    ObjectDisposedException

    如果在处理过程中需要停止计时器,并且计时器委托中的工作可能仍在进行中,这依赖于共享资源,同时被处理,则需要协调“关机”过程。下面的代码片段显示了执行此操作的示例:

    public class PeriodicTimerTask : IDisposable
    {
        private readonly System.Timers.Timer _timer;
        private CancellationTokenSource _tokenSource;
        private readonly ManualResetEventSlim _callbackComplete;
        private readonly Action<CancellationToken> _userTask;
    
        public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
        {
            _tokenSource = new CancellationTokenSource();
            _userTask = userTask;
            _callbackComplete = new ManualResetEventSlim(true);
            _timer = new System.Timers.Timer(interval.TotalMilliseconds);
        }
    
        public void Start()
        {
            if (_tokenSource != null)
            {
                _timer.Elapsed += (sender, e) => Tick();
                _timer.AutoReset = true;
                _timer.Start();
            }
        }
    
        public void Stop()
        {
            var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
            if (tokenSource != null)
            {
                _timer.Stop();
                tokenSource.Cancel();
                _callbackComplete.Wait();
                _timer.Dispose();
                _callbackComplete.Dispose();
                tokenSource.Dispose();
            }
        }
    
        public void Dispose()
        {
            Stop();
            GC.SuppressFinalize(this);
        }
    
        private void Tick()
        {
            var tokenSource = _tokenSource;
            if (tokenSource != null && !tokenSource.IsCancellationRequested)
            {
                try
                {
                    _callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
                    _callbackComplete.Reset();
                    try
                    {
                        tokenSource = _tokenSource;
                        if (tokenSource != null && !tokenSource.IsCancellationRequested)
                            _userTask(tokenSource.Token);
                    }
                    finally
                    {
                        _callbackComplete.Set();
                    }
                }
                catch (OperationCanceledException) { }
            }
        }
    }
    
    公共类PeriodicTimerTask:IDisposable
    {
    专用只读系统.Timers.Timer\u Timer;
    私有取消令牌源\u令牌源;
    专用只读手册ResetEventSlim\u callbackComplete;
    私有只读操作_userTask;
    公共周期ICTimerTask(时间跨度间隔,操作用户任务)
    {
    _tokenSource=新的CancellationTokenSource();
    _userTask=userTask;
    _callbackComplete=新的ManualResetEventSlim(真);
    _计时器=新系统.计时器.计时器(间隔.总毫秒);
    }
    公开作废开始()
    {
    if(_tokenSource!=null)
    {
    _timer.appead+=(发送方,e)=>勾选();
    _timer.AutoReset=true;
    _timer.Start();
    }
    }
    公共停车场()
    {
    var tokenSource=Interlocked.Exchange(ref\u tokenSource,null);
    if(令牌源!=null)
    {
    _timer.Stop();
    tokenSource.Cancel();
    _callbackComplete.Wait();
    _timer.Dispose();
    _callbackComplete.Dispose();
    tokenSource.Dispose();
    }
    }
    公共空间处置()
    {
    停止();
    总干事(本);
    }
    私人空白勾号()
    {
    var tokenSource=\u tokenSource;
    if(tokenSource!=null&&!tokenSource.IsCancellationRequested)
    {
    尝试
    {
    _callbackComplete.Wait(tokenSource.Token);//防止多个记号。
    _callbackComplete.Reset();
    尝试
    {
    令牌源=_令牌源;
    if(tokenSource!=null&&!tokenSource.IsCancellationRequested)
    _userTask(tokenSource.Token);
    }
    最后
    {
    _callbackComplete.Set();
    }
    }
    捕获(操作取消异常){}
    }
    }
    }
    
    用法示例:

    public static void Main(params string[] args)
    {
        var periodic = new PeriodicTimerTask(TimeSpan.FromSeconds(1), cancel => {
            int n = 0;
            Console.Write("Tick ...");
            while (!cancel.IsCancellationRequested && n < 100000)
            {
                n++;
            }
            Console.WriteLine(" completed.");
        });
        periodic.Start();
        Console.WriteLine("Press <ENTER> to stop");
        Console.ReadLine();
        Console.WriteLine("Stopping");
        periodic.Dispose();
        Console.WriteLine("Stopped");
    }
    
    publicstaticvoidmain(参数字符串[]args)
    {
    var periodic=new PeriodicTimerTask(TimeSpan.FromSeconds(1),cancel=>{
    int n=0;
    控制台。写(“勾选…”);
    而(!cancel.IsCancellationRequested&&n<100000)
    {
    n++;
    }
    Console.WriteLine(“已完成”);
    });
    periodic.Start();
    控制台。写入线(“按下停止”);
    Console.ReadLine();
    控制台。写入线(“停止”);
    periodic.Dispose();
    控制台。写入线(“停止”);
    }
    
    输出如下:

    Press <ENTER> to stop
    Tick ... completed.
    Tick ... completed.
    Tick ... completed.
    Tick ... completed.
    Tick ... completed.
    
    Stopping
    Stopped
    
    按下可停止
    勾选…完成。
    勾选…完成。
    勾选…完成。
    勾选…完成。
    勾选…完成。
    停止
    停止
    
    如果在处理过程中需要停止计时器,并且计时器委托中的工作可能仍在进行中(该委托依赖于共享资源),同时被处理,则需要协调“关闭”过程。下面的代码片段显示了这样做的示例:

    public class PeriodicTimerTask : IDisposable
    {
        private readonly System.Timers.Timer _timer;
        private CancellationTokenSource _tokenSource;
        private readonly ManualResetEventSlim _callbackComplete;
        private readonly Action<CancellationToken> _userTask;
    
        public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
        {
            _tokenSource = new CancellationTokenSource();
            _userTask = userTask;
            _callbackComplete = new ManualResetEventSlim(true);
            _timer = new System.Timers.Timer(interval.TotalMilliseconds);
        }
    
        public void Start()
        {
            if (_tokenSource != null)
            {
                _timer.Elapsed += (sender, e) => Tick();
                _timer.AutoReset = true;
                _timer.Start();
            }
        }
    
        public void Stop()
        {
            var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
            if (tokenSource != null)
            {
                _timer.Stop();
                tokenSource.Cancel();
                _callbackComplete.Wait();
                _timer.Dispose();
                _callbackComplete.Dispose();
                tokenSource.Dispose();
            }
        }
    
        public void Dispose()
        {
            Stop();
            GC.SuppressFinalize(this);
        }
    
        private void Tick()
        {
            var tokenSource = _tokenSource;
            if (tokenSource != null && !tokenSource.IsCancellationRequested)
            {
                try
                {
                    _callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
                    _callbackComplete.Reset();
                    try
                    {
                        tokenSource = _tokenSource;
                        if (tokenSource != null && !tokenSource.IsCancellationRequested)
                            _userTask(tokenSource.Token);
                    }
                    finally
                    {
                        _callbackComplete.Set();
                    }
                }
                catch (OperationCanceledException) { }
            }
        }
    }
    
    公共类PeriodicTimerTask:IDisposable
    {
    专用只读系统.Timers.Timer\u Timer;
    私有取消令牌源\u令牌源;
    专用只读手册ResetEventSlim\u callbackComplete;
    私有只读操作_userTask;
    公共周期ICTimerTask(时间跨度间隔,操作用户任务)
    {
    _tokenSource=新的CancellationTokenSource();
    _userTask=userTask;
    _callbackComplete=新的ManualResetEventSlim(真);
    _钛