c# - Multiple timer/callbacks — best approach to prevent duplicates and to monitor them -


i have c# console, have made windows service, run reliably , constantly.

  1. i want prevent overlap of same timer firing again
  2. i want prevent different timers trying use same resource @ once
  3. i want able monitor timers , interact then.

it has few aspects it. each runs regularly. have read taskscheduler vs windows service running kind of thing, , have opted approach because running constantly.

  • tasktype1
  • tasktype2
  • tasktype3
  • tasktype4

i'm using timer callbacks, each own, similar simplified version:

class program {     static pollingservice _service;      static void main()     {         _service = new pollingservice();          timercallback tc1 = _service.tasktype1;         timercallback tc2 = _service.tasktype2;         timercallback tc3 = _service.tasktype3a;         timercallback tc4 = _service.tasktype3b;          timer t1 = new timer(tc1, null, 1000, 5000);         timer t2 = new timer(tc2, null, 2000, 8000);         timer t3 = new timer(tc3, null, 3000, 11000);         timer t4 = new timer(tc4, null, 4000, 13000);           console.writeline("press q quit");         while (console.readkey(true).keychar != 'q')         {         }     } }  class pollingservice {     public void tasktype1(object state)     {         (int = 1; <= 10; i++)         {             console.writeline($"taskone numbering {i}");             thread.sleep(100);         }     }      public void tasktype2(object state)     {         (int = 10; <= 100; i++)         {             console.writeline($"tasktwo numbering {i}");             thread.sleep(100);         }     }      public void tasktype3a(object state)     {         increment(200000000);     }      public void tasktype3b(object state)     {         increment(40000);     }      private void increment(int startnumber)     {         (int = startnumber; <= startnumber + 1000; i++)         {             console.writeline($"private {startnumber} numbering {i}");             thread.sleep(5);         }     } } 

1 firstly want ensure these don't tied each other when 1 runs long.
eg. if task 1 takes 20 seconds run sometimes, want prevent duplicate timer while previous might still running, same of timers infact. eg. if t2 running little longer usual don't start another. i've read little if (monitor.tryenter(lockobject)), best way handle requirement?

2 secondly if both access same resource (in case ef context), such t3 using it, , t4 tries so. there way of asking timer wait until other finishes?

3 lastly there way can monitor these timer/callbacks? i'd provide ui see state of when have running windows service. endgame there provide ui users can see if task running, , if not trigger on demand if 1 isn't set run little while. in same breath, not create duplicate while 1 running.

i have wondered whether should've asked these separate questions, seem entwined decision of each other.

if have make sure each thread doesn't have overlap, can use timer.change(int, int) method stop executing @ start of callback, , resume @ end of callback. can magic manualresetevent each thread it'll messy.

i'm not fan of timers threading , try avoid them whenever can. if can sacrifice "each thread must run after n seconds", it. use tasks cancellation token instead, solve overlap problem. example:

a.

public class foo {     private cancellationtokensource _cts;     //in case care tasks have.     private list< task > _tasks;      public foo()     {         this._cts = new cancellationtokensource();          this._tasks.add(task.factory.startnew(this.method1, this._cts.token));         this._tasks.add(task.factory.startnew(this.method2, this._cts.token));         this._tasks.add(task.factory.startnew(this.method3, this._cts.token));         this._tasks.add(task.factory.startnew(this.method4, this._cts.token));       }      private void method1(object state)     {         var token = (cancellationtoken) state;         while ( !token.iscancellationrequested )         {             //do stuff         }      }     private void method2(object state)     {         var token = (cancellationtoken)state;         while (!token.iscancellationrequested)         {             //do stuff         }     }     private void method3(object state)     {         var token = (cancellationtoken)state;         while (!token.iscancellationrequested)         {             //do stuff         }     }     private void method4(object state)     {         var token = (cancellationtoken)state;         while (!token.iscancellationrequested)         {             //do stuff         }     }      public void stopexecution()     {         this._cts.cancel();     } } 

an ef context throw exception if used more 1 thread @ time. there way synchronize it, using lock. this, given example above:

b.

public class foo {     private object _eflock;     public foo()     {         this._eflock = new object();     } . . .     private void methodx(object state)     {         var token = (cancellationtoken)state;         while (!token.iscancellationrequested)         {             lock(this._eflock)             {                  using(.......             }         }     } } 

you'll have in each thread accesses ef context. keep in mind that, again, maintenance gets annoying because of cognitive load goes complex lock scenarios.

i developed application in needed multiple threads access same ef context. mentioned above, locking got (and there performance requirement), devised solution each thread adds object common queue, , separate thread nothing pull data queue , call ef. way ef context ever accessed 1 thread. problem solved. here given sample above:

c.

public class foo {     private struct internalefdata     {         public int someproperty;     }       private cancellationtokensource _datacreatorcts;     private cancellationtokensource _efcts;      //in case care tasks have.     private list< task > _tasks;     private task _entityframeworktask;      private concurrentbag< internalefdata > _efdata;       public foo()     {         this._efdata = new concurrentbag< internalefdata >();          this._datacreatorcts = new cancellationtokensource();         this._efcts = new cancellationtokensource();          this._entityframeworktask = task.factory.startnew(this.processefdata, this._efcts.token);          this._tasks.add(task.factory.startnew(this.method1, this._datacreatorcts.token));         this._tasks.add(task.factory.startnew(this.method2, this._datacreatorcts.token));         .         .         .      }      private void processefdata(object state)     {         var token = (cancellationtoken) state;         while ( !token.iscancellationrequested )         {             internalefdata item;             if (this._efdata.trytake(out item))             {                 using ( var efcontext = new mydbcontext() )                 {                     //do processing.                     }             }         }      }      private void method1(object state)     {         var token = (cancellationtoken) state;         while ( !token.iscancellationrequested )         {             //get data whatever source             this._efdata.add(new internalefdata());         }      }      private void method2(object state)     {         var token = (cancellationtoken) state;         while ( !token.iscancellationrequested )         {             //get data whatever source             this._efdata.add(new internalefdata());         }     }       public void stopexecution()     {         this._datacreatorcts.cancel();         this._efcts.cancel();     } } 

when comes reading data executing threads, use synchronizationcontext. don't know if it's right object use , else can comment on that. create synchronization object, pass threads , have them update necessary data , post ui/console thread:

d.

public struct syncobject {     public int somefield; }  public delegate void synchandler(syncobject s);  public class synchronizer {     public event synchandler onsynchronization;      private synchronizationcontext _context;      public synchronizer()     {         this._context = new synchronizationcontext();     }      public void postupdate(syncobject o)     {         var handlenullrefs = this.onsynchronization;         if ( handlenullrefs != null )         {             this._context.post(state => handlenullrefs((syncobject)state), o);         }     } }  public class foo {     private synchronizer _sync;     public foo(synchronizer s)     {         this._sync = s;     }     private void method1(object state)     {         var token = (cancellationtoken) state;         while ( !token.iscancellationrequested )         {             //do things             this._sync.postupdate(new syncobject());         }      } } 

again, that's how it, don't know if it's proper way.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -