秒表在单独的线程重启

本文关键字:线程 重启 单独 | 更新日期: 2023-09-27 18:01:18

我有一个客户端-服务器应用程序,我想定期检查客户端是否与服务器断开连接。

我已经决定检查传入的数据包。如果我在15秒的时间范围内收到任何消息,我就有一个有效的连接,如果没有,我已断开连接,将尝试重新连接。

到目前为止,我有这个示例代码(这是从我的代码重新创建的示例):
namespace TimerExample
{
    class Program
    {
        static void Main(string[] args)
        {
           HandlePackets();
        }
        public void HandlePackets()
        {
            //code that handles incomming packets
            foo test = new foo();
            test.StartThread();
        }
    }
    class foo
    {
        public bool _isRunning { get; set; }
        private Stopwatch sw { get; set; }
        public void StartThread()
        {
            this._isRunning = true;
            new Thread(new ThreadStart(this.DoWork)).Start();
            this.sw.Restart();
        }
        public void StopThread()
        {
            this._isRunning = false;
            this.sw.Stop();
        }
        private void DoWork()
        {
            while (this._isRunning)
            {
                Console.WriteLine("Elapsed in miliseconds: " + this.GetRuntime().ToString());
                if (GetRuntime() > 15000)
                {
                    Console.WriteLine("Client disconnected.... restarting");
                    this.StopThread();
                }
                Thread.Sleep(1000);
            }
        }
        public long GetRuntime()
        {
            return this.sw.ElapsedMilliseconds;
        }
        public foo()
        {
            _isRunning = false;
            sw = new Stopwatch();
        }
    }
}

我想让代码做的是:函数HandlePackets将在每次数据包到达时执行。在这个函数中我将调用函数StartThread,它将在单独的线程中运行Stopwatch,并且只要stopwatch经过的时间以毫秒为单位,此进程将继续进行不会超过15秒。

如果它会,我会调用Reconnect

所以基本上每次收到数据包时timer都会重新启动,如果ElapsedTime大于15秒,则会调用reconnect。

秒表在单独的线程重启

有几种方法可以实现此机制。

创建线程是最糟糕的。注意,从多个线程访问Stopwatch实例成员是不安全的。

一个简单直接的解决方案是创建ThreadPool Timer,让它每15秒滴答一次,并通过Volatile.Read检查布尔变量。一旦布尔变量为False -您可以重新连接。从接收线程,您只需要设置变量使用Volatile.Write true。这在接收(几乎)时不会消耗资源。

在许多实现中,由于重新连接机制可以在新数据包到达之前开始,因此可能存在竞争。改善这种情况的最简单的方法是在您决定重新连接之前停止计时器,并在连接完成后重新启动计时器。您必须明白,没有办法解决这个错误的重新连接问题。

上述方法的工作原理与WatchDog

非常相似

从设计的角度来看,我建议您创建类:Receiver和WatchDog和ConnectionManager

// Receives and processes data
class Receiver : IDisposable
{
  public Receiver(WatchDog watchDog);
  public void LoopReceive(); // Tick watch dog on every packet
  public void Dispose();
}
// Setups timer and periodically checks if receiver is alive.
// If its not, it asks manager to reconnect and disposes receiver
class WatchDog : IDisposable
{
  public WatchDog(ConnectionFactory factory);
  // Setups timer, performs Volatile.Read and if receiver is dead, call dispose on it and ask manager to reconnect.
  public void StartWatching(IDisposable subject);
  public void Tick(); // Volatile.Write
  public void Dispose();
}
// Can re-connect and create new instances of timer and watchdog
// Holds instance variable of receiver created
class ConnectionManager
{
  public void Connect();
  // disposes watch dog and calls connect
  public void ReConnect(WatchDog watchDog);
}

PS:波动。对于标志变量

, *可以用volatile关键字代替