Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Threads, Static Fields & Abstract Classes Problem

Threads, Static Fields & Abstract Classes Problem

Scheduled Pinned Locked Moved C#
help
4 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JohnLBevan
    wrote on last edited by
    #1

    Hi Folks, I'm hoping someone can help me with an issue I've just come across. I’ve written the demo code below which shows that if I use a timer to schedule events, unless I use a static “sync” variable, a second instance of a class may begin running before the first has completed. Rather than relying on folk remembering and repeating this logic, I’m hoping to put it into an abstract base class, which then calls a method in the subclass to do the processing, safe in the knowledge that another instance of that same class won’t run until this one’s completed. However, if there’s another class deriving from this base class, I’d want instances of the new class to be unaffected by instances of the first subclass (i.e. effectively I want the sync field to be static in the subclass, but available to the base class).

    class Program
    {
        static void Main(string\[\] args)
        {
            Base one = new SubClass1();
            Base two = new SubClass2();
            Timer timer1 = new Timer();
            Timer timer2 = new Timer();
            timer1.Interval = 3000;
            timer1.Elapsed += new ElapsedEventHandler(one.Run);
            timer1.Enabled = true;
            timer2.Interval = 5000;
            timer2.Elapsed += new ElapsedEventHandler(two.Run);
            timer2.Enabled = true;System.Threading.Thread.Sleep(20000);
            Console.ReadKey();//allows the program to stay alive whilst the threads continue
        }      
    }
    abstract class Base
    {
        private volatile static bool sync = false;
        private static object syncroot = string.Empty;
        public void Run(object source, ElapsedEventArgs e)
        {
            if (sync) return;
            lock (syncroot)
            {
                if (sync) return;
                sync = true;
            }
            RunSubClassCode();
            sync = false;
        }
        protected abstract void RunSubClassCode();
    }
    class SubClass1: Base
    {
        protected override void RunSubClassCode()
        {
            Console.WriteLine("1a");
            System.Threading.Thread.Sleep(2000);
            Console.WriteLine("1b");
        }
    }
    class SubClass2 : Base
    {
        protected override void RunSubClassCode()
        {
            Console.WriteLine("2a");
            System.Threading.Thread.Sleep(2000);
            Console.WriteLine("2b");
        }
    }
    

    Has anyone come across a similar requirement before, or can y

    L 1 Reply Last reply
    0
    • J JohnLBevan

      Hi Folks, I'm hoping someone can help me with an issue I've just come across. I’ve written the demo code below which shows that if I use a timer to schedule events, unless I use a static “sync” variable, a second instance of a class may begin running before the first has completed. Rather than relying on folk remembering and repeating this logic, I’m hoping to put it into an abstract base class, which then calls a method in the subclass to do the processing, safe in the knowledge that another instance of that same class won’t run until this one’s completed. However, if there’s another class deriving from this base class, I’d want instances of the new class to be unaffected by instances of the first subclass (i.e. effectively I want the sync field to be static in the subclass, but available to the base class).

      class Program
      {
          static void Main(string\[\] args)
          {
              Base one = new SubClass1();
              Base two = new SubClass2();
              Timer timer1 = new Timer();
              Timer timer2 = new Timer();
              timer1.Interval = 3000;
              timer1.Elapsed += new ElapsedEventHandler(one.Run);
              timer1.Enabled = true;
              timer2.Interval = 5000;
              timer2.Elapsed += new ElapsedEventHandler(two.Run);
              timer2.Enabled = true;System.Threading.Thread.Sleep(20000);
              Console.ReadKey();//allows the program to stay alive whilst the threads continue
          }      
      }
      abstract class Base
      {
          private volatile static bool sync = false;
          private static object syncroot = string.Empty;
          public void Run(object source, ElapsedEventArgs e)
          {
              if (sync) return;
              lock (syncroot)
              {
                  if (sync) return;
                  sync = true;
              }
              RunSubClassCode();
              sync = false;
          }
          protected abstract void RunSubClassCode();
      }
      class SubClass1: Base
      {
          protected override void RunSubClassCode()
          {
              Console.WriteLine("1a");
              System.Threading.Thread.Sleep(2000);
              Console.WriteLine("1b");
          }
      }
      class SubClass2 : Base
      {
          protected override void RunSubClassCode()
          {
              Console.WriteLine("2a");
              System.Threading.Thread.Sleep(2000);
              Console.WriteLine("2b");
          }
      }
      

      Has anyone come across a similar requirement before, or can y

      L Offline
      L Offline
      Luc Pattyn
      wrote on last edited by
      #2

      you are correct, timer handlers can overlap (unless you use a System.Windows.Forms.Timer which has special characteristics). There are several ways to deal with that, which one you choose may depend on circumstances. Here is a scheme a like a lot because it is simple: - ask the timer to tick only once, then call your handler; - in the handler, when all is done, again arm the timer for a single shot. The advantage is there is no risk of overlap, and what you are doing in fact is time the idle part of the period, so if the handler takes 3 seconds, and you set the timer to 7 seconds, then your action will run every 10 seconds; if for some reason it takes longer, then all later timer activities will also come later. The scheme can easily be implemented using the System.Threading.Timer and its Change() method. If you really want to time the period, i.e. the start point (and not the idle gap), then it is always trickier to get it right under all circumstances. However IMO the fixed gap is what most applications want. :)

      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


      I only read formatted code with indentation, so please use PRE tags for code snippets.


      I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


      J 1 Reply Last reply
      0
      • L Luc Pattyn

        you are correct, timer handlers can overlap (unless you use a System.Windows.Forms.Timer which has special characteristics). There are several ways to deal with that, which one you choose may depend on circumstances. Here is a scheme a like a lot because it is simple: - ask the timer to tick only once, then call your handler; - in the handler, when all is done, again arm the timer for a single shot. The advantage is there is no risk of overlap, and what you are doing in fact is time the idle part of the period, so if the handler takes 3 seconds, and you set the timer to 7 seconds, then your action will run every 10 seconds; if for some reason it takes longer, then all later timer activities will also come later. The scheme can easily be implemented using the System.Threading.Timer and its Change() method. If you really want to time the period, i.e. the start point (and not the idle gap), then it is always trickier to get it right under all circumstances. However IMO the fixed gap is what most applications want. :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


        I only read formatted code with indentation, so please use PRE tags for code snippets.


        I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


        J Offline
        J Offline
        JohnLBevan
        wrote on last edited by
        #3

        Hey Luc, that's a great idea; thanks again for your help. For anyone following this thread (no pun intended), below is an example of the demo code, updated to use this idea (hopefully this agrees with what Luc's described - it definitely works as hoped).

        class Example4
        {
            public static void Test()
            {
                Base4 one = new SubClass4\_1();
                Base4 two = new SubClass4\_2();
                one.Go();
                two.Go();
                System.Threading.Thread.Sleep(20000); //give the threads time to do stuff before terminating
                one.Stop();
                two.Stop();
            }
        }
        
        abstract class Base4
        {
            DateTime lastRun = DateTime.UtcNow;
            Timer timer = new Timer();
            public void Go()
            {
                timer.AutoReset = false; //run once (until manually enabled in Again())
                timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
                timer.Interval = GetInterval();
                timer.Enabled = true;
            }
            public void Stop()
            {
                timer.Close();
                timer.Dispose();
                //nb: code in thread runs to completion even after timer has been disposed of
            }
            private void OnElapsedTime(object source, ElapsedEventArgs e)
            {
                lastRun = DateTime.UtcNow;
                RunSubClassCode();
                Again();
            }
        
            private void Again()
            {
                //acount for delay caused by the app running
                int interval = GetIntervalAccountForProcessingTime();
                try //stops the "loop" when the timer is disposed of, without exception
                {
                    timer.Interval = interval;
                    timer.Enabled = true;//kick things off again
                }
                catch (ObjectDisposedException) { } 
        
            }
            private int GetIntervalAccountForProcessingTime()
            {
                int interval = GetInterval();
                interval -= DateTime.UtcNow.Subtract(lastRun).Milliseconds;
                interval = Math.Max(interval, 1);                                   //if we've gone past the period, kick it off straight away
                //while (interval < GetInterval()) interval += GetInterval();       //if we want to wait for the next interval/slot, replace the above line with this code
                return interval;
            }
            protected abstract int GetInterval();
            protected abstract void RunSubClassCode();
        }
        
        class SubClass4\_1 :
        
        L 1 Reply Last reply
        0
        • J JohnLBevan

          Hey Luc, that's a great idea; thanks again for your help. For anyone following this thread (no pun intended), below is an example of the demo code, updated to use this idea (hopefully this agrees with what Luc's described - it definitely works as hoped).

          class Example4
          {
              public static void Test()
              {
                  Base4 one = new SubClass4\_1();
                  Base4 two = new SubClass4\_2();
                  one.Go();
                  two.Go();
                  System.Threading.Thread.Sleep(20000); //give the threads time to do stuff before terminating
                  one.Stop();
                  two.Stop();
              }
          }
          
          abstract class Base4
          {
              DateTime lastRun = DateTime.UtcNow;
              Timer timer = new Timer();
              public void Go()
              {
                  timer.AutoReset = false; //run once (until manually enabled in Again())
                  timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
                  timer.Interval = GetInterval();
                  timer.Enabled = true;
              }
              public void Stop()
              {
                  timer.Close();
                  timer.Dispose();
                  //nb: code in thread runs to completion even after timer has been disposed of
              }
              private void OnElapsedTime(object source, ElapsedEventArgs e)
              {
                  lastRun = DateTime.UtcNow;
                  RunSubClassCode();
                  Again();
              }
          
              private void Again()
              {
                  //acount for delay caused by the app running
                  int interval = GetIntervalAccountForProcessingTime();
                  try //stops the "loop" when the timer is disposed of, without exception
                  {
                      timer.Interval = interval;
                      timer.Enabled = true;//kick things off again
                  }
                  catch (ObjectDisposedException) { } 
          
              }
              private int GetIntervalAccountForProcessingTime()
              {
                  int interval = GetInterval();
                  interval -= DateTime.UtcNow.Subtract(lastRun).Milliseconds;
                  interval = Math.Max(interval, 1);                                   //if we've gone past the period, kick it off straight away
                  //while (interval < GetInterval()) interval += GetInterval();       //if we want to wait for the next interval/slot, replace the above line with this code
                  return interval;
              }
              protected abstract int GetInterval();
              protected abstract void RunSubClassCode();
          }
          
          class SubClass4\_1 :
          
          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          you're welcome. :)

          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


          I only read formatted code with indentation, so please use PRE tags for code snippets.


          I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).


          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups