c# - Assist the UI Dispatcher to handle a flood of method invocations -


the following post has become bit *longer* expected apologize maybe you'll find interesting read , maybe have idea me :)

i developing small application gui consists of number of list controls. each list control has thread associated permanently producing strings being added list.

to allow list controls being updated different threads built extended observablecollection asynchronously invokes operations ui dispatcher works pretty fine. here code-snippet of class examplify insert-operation:

public class threadsaveobservablecollection<t> : observablecollection<t> {      private int _index;      private dispatcher _uidispatcher;     private readerwriterlock _rwlock;      // ...      private bool _insertregflag;      new public void insert (int index, t item) {          if (thread.currentthread == _uidispatcher.thread) {              insert_(index, item);         } else {              if (_insertregflag) { }             else {                  bufferedinvoker.registermethod(_index + "." + (int)methods.insert);                 _insertregflag = true;             }              bufferedinvoker.addinvocation(new invocation<int, t> { ident = _index + "." + (int)methods.insert, dispatcher = _uidispatcher, priority = dispatcherpriority.normal, param1 = index, param2 = item, method = new action<int, t>(insert_) });         }     }      private void insert_ (int index, t item) {          _rwlock.acquirewriterlock(timeout.infinite);          datetime timestampa = datetime.now;          base.insert(index, item);          datetime timestampb = datetime.now;          bufferedinvoker.returned(_index + "." + (int)methods.insert, timestampb.subtract(timestampa).totalmilliseconds);          _rwlock.releasewriterlock();     }      // ... } 

to model invocation in form of kind of pending invocation-task built following:

public interface iinvocation {      string ident { get; set; }     void invoke (); }  public struct invocation : iinvocation {      public string ident { get; set; }     public dispatcher dispatcher { get; set; }     public dispatcherpriority priority { get; set; }     public delegate method { get; set; }      public void invoke () {          dispatcher.begininvoke(method, priority, new object[] { });     } } 

my problem because of enormous amount of method calls invoking onto ui dispatcher (i have aprox. 8 10 threads permanently producing strings add lists) ui looses ability respond user i/o (e.g. mouse) after aprox. 30 seconds until doesn't accept user interaction @ after minute.

to face problem wrote kind of buffered invoker responsible buffering method calls want invoke onto ui dispatcher invoke them in controlled way e.g. delay between invocations avoid flooding ui dispatcher.

here code illustrate doing (please see description after code-segment):

public static class bufferedinvoker {      private static long _invoked;     private static long _returned;     private static long _pending;     private static bool _isinbalanced;      private static list<iinvocation> _workload;     private static queue<iinvocation> _queue;      private static thread _enqueuingthread;     private static thread _dequeuingthread;     private static manualresetevent _terminatesignal;     private static manualresetevent _enqueusignal;     private static manualresetevent _dequeuesignal;      public static void addinvocation (iinvocation invocation) {          lock (_workload) {              _workload.add(invocation);             _enqueusignal.set();         }     }      private static void _enqueuing () {          while (!_terminatesignal.waitone(0, false)) {              if (_enqueusignal.waitone()) {                  lock (_workload) {                      lock (_queue) {                          if (_workload.count == 0 || _queue.count == 20) {                              _enqueusignal.reset();                             continue;                         }                          iinvocation item = _workload[0];                         _workload.removeat(0);                         _queue.enqueue(item);                          if (_queue.count == 1) _dequeuesignal.set();                     }                 }             }         }     }      private static void _dequeuing () {          while (!_terminatesignal.waitone(0, false)) {              if (_dequeuesignal.waitone()) {                  lock (_queue) {                      if (_queue.count == 0) {                          _dequeuesignal.reset();                         continue;                     }                      thread.sleep(delay);                      iinvocation = _queue.dequeue();                     i.invoke();                      _invoked++;                     _waiting = _triggered - _invoked;                 }             }         }     }      public static void returned (string ident, double duration) {          _returned++;          // ...     } } 

the idea behind bufferedinvoker observablecollections don't invoke operations on own instead call addinvocation method of bufferedinvoker puts invocation-task _workload list. bufferedinvoker maintains 2 'internal' threads operate on _queue - 1 thread takes invocations _workload list , puts them _queue , other thread puts invocations out of _queue , invokes them 1 after other.

so that's nothing else 2 buffers store pending invocation-tasks in order delay actual invocation. further counting number of invocation-tasks have been invoked _dequeuing thread (i.e. long _invoked) , number of methods have been returned execution (every method inside observablecollection calls returned() method of bufferedinvoker when completes execution - number stored inside _returned variable.

my idea number of pending invocations (_invoked - _returned) feeling of workload of ui dispatcher - surprisingly _pending below 1 or 2.

so problem although delaying invocations of methods ui dispatcher (with thread.sleep(delay)) application starts lag after time reflects fact ui has handle user i/o.

but - , wondering - _pending counter never reaches high value, of time it's 0 if ui has been frozen.

so have find

(1) way measure workload of ui dispatcher determine point ui dispatcher over-worked and

(2) against it.

so thank reading until point , hope have ideas how invoke arbitrary high number of methods onto ui dispatcher without overwhelming it..

thank in advance ...emphasized text*emphasized text*

having taken quick notice sleep lock held. means while sleeping no 1 can enqueue, rendering queue useless.

the application not lag because queue busy, because lock held always.

i think you'll better off removing manually implemented queues , locks , monitors , use built-in concurrentqueue. 1 queue per ui control , thread, , 1 timer per queue.

anyway, here propose:

concurrentqueue<item> queue = new ...;  //timer pulls every 100ms or var timer = new timer(_ => {  var localitems = new list<item>();  while(queue.trydequeue(...)) { localitems.add(...); }  if(localitems.count != 0) { pushtoui(localitems); } });  //producer pushes unlimited amounts new thread(() => { while(true) queue.enqueue(...); }); 

simple.


Comments

Popular posts from this blog

c# - SVN Error : "svnadmin: E205000: Too many arguments" -

c# - Copy ObservableCollection to another ObservableCollection -

All overlapping substrings matching a java regex -