> Oh, and the Tablet PC's Ink API fires some events on background
threads...
> Go figure, eh?

Firing events from background threads for consumption in the UI is the
hardest problem (for me) that I face at the moment.

If I have a long running process that needs to invoke events that the UI
has hooked then if I run this in a worker thread and trigger the events
the event handlers will execute on the worker thread before continuing.
This worker thread is not allowed to update the UI, so I have to invoke
onto the UI thread in the event handler. After I invoke onto the UI
thread I can't call into the model for the state that I need to render,
because the worker thread may have locked the model which would cause
the UI thread to block while waiting for its state.

There are only two solutions that I can see. Have my business model
throw immutable state objects with the event (i.e. EventArgs), or have
the business model queue events and dispatch them on the UI thread when
the worker thread has run to completion.

For example, say I have a thread safe Person class like this (in pseudo
code):

public Person {
  public int Id { get; }
  public event NameChanged;
  public string Name { get; set; }
  public event PhoneChanged;
  public string Phone { get; set; }
  public void SyncWithDatastore(
    this.Name = GetNameFromWebService(this.Id);
    this.Phone = GetPhoneFromDatabase(this.Id);
    // etc.
  )
}

If SyncWithDatastore() has to hit say a few disparate datasources, say
one via a WebService and another in ActiveDirectory or a DB or
something, then this could be a long running process, particularly if
there is a problem that waits for a timeout.

If I call SyncWithDatastore() from the UI thread then the NameChanged
event would fire, then the PhoneChanged event and this would be fine and
could be handled along the way on the UI thread, the problem is that the
UI thread is blocked until the method completes.

If I fire it on a worker thread, then the event handlers execute on the
worker thread, if I invoke these onto the UI thread I can't then have a
handler like this:

void HandleNameChanged() {
  this.Text = this.Person.Name;
}

because calling into the Person.Name getter may cause the UI to block
(assuming it is thread safe, if it's not thread safe then this would be
a really bad idea anyway).

So I'm really trying to figure out a way that I can have my cake and eat
it too. I don't really want to create a business model that throws state
with its events, because I'd be uselessly creating objects in scenarios
where my business objects don't need to run in a thread safe manner, I
guess too because I've never seen anyone else do this. :P The other idea
that I'm entertaining is that rather than invoking the events, I just
stash the event delegates on a FIFO queue and then dispatch them all
once the worker thread returns (in the UI thread on EndInvoke for
example), this second option is kind of attractive, because it is more
'atomic' in the sense that if I fail half way through I can decide
whether I want to dispatch the events or not, etc. (although that seems
like it might start getting really complicated).

I guess for this simple example, the properties wouldn't be locked for
very long at all, so maybe it is OK to just invoke the event onto the UI
thread and then read out of the model, assuming that it probably isn't
locked and if it is it won't be for long. But some processes would lock
for longer. Say for example (and this may be a really poor example, or a
bad thing to do) I had another business object that had hooked the
PhoneChanged event for some reason, and this event was going to run on
the worker thread, say the first event the worker thread fires is for
the UI control, then as it is invoked onto the UI it races the
invocation of the next handler, if the next handler wins, it might run
some long running process and the UI is now blocked. Or perhaps not, if
the events are invoked outside the critical section.. at any rate, this
problem has still got my mind in knots.

I haven't seen anything that I've really groked wrt to these ideas. Does
anyone have any thoughts on this, or know where I can find some good
material?

Basically: multithreaded MVC in WinForms.

John.

===================================
This list is hosted by DevelopMentorŪ  http://www.develop.com
Some .NET courses you may be interested in:

NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles
http://www.develop.com/courses/gaspdotnetls

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to