Tagyoureit
Tagyoureit

Reputation: 379

StopWatch in separate thread restart

I have a client - server application and I want to check periodically if client has disconnected from server.

I have decided that I will check for incoming packets. If i received any in time span of let say 15 seconds I have a valid connection, if not I have disconnected and will try to reconnect.

So far I have this sample code (this is sample recreated from my code):

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();
        }
    }
}

What I want for code to be doing is: Function HandlePackets will be executed every time packet will arrive. Inside that function I will call function StartThread which will run Stopwatch in separate thread and this process will go on as long as stopwatch elapsed time in milliseconds won't be bigger than lets say 15 seconds.

If it will I will call Reconnect.

So basically timer will restart every time a packet is received and reconnect will be called if ElapsedTime will be greater than 15 seconds.

Upvotes: 0

Views: 477

Answers (1)

PavPS
PavPS

Reputation: 76

There are several ways to implement this mechanism.

Creating thread is the worst one. Be careful - accessing Stopwatch instance members from multiple threads is not safe.

One easy and straightforward solution is to create ThreadPool Timer that ticks let's say every 15 seconds and checks boolean variable via Volatile.Read. Once boolean variable is False - you can re-connect. From receiver thread you just need to set variable using Volatile.Write true. This does not consume resources when receiving (almost).

In many of the implementations could be races because of re-connection mechanism that can start a moment before new packet arrives. The easiest and rogue way to improve this is to stop timer right before you decide to re-connect and start it again once connection is done. You must understand that there is no way to solve this false-reconnection issue.

The method above works pretty much like WatchDog

From design perspective I would recommend you create classes : Receiver and WatchDog and 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.* could be replaced with volatile keyword for the flag variable

Upvotes: 1

Related Questions