Well I stand corrected - I just looked at the code using Reflector and
that’s exactly what happens :-)

Regards

Richard Blewett
DevelopMentor

> -----Original Message-----
> From: Moderated discussion of advanced .NET topics. [mailto:ADVANCED-
> [EMAIL PROTECTED] On Behalf Of Dmitriy Zaslavskiy
> Sent: 01 March 2004 19:18
> To: [EMAIL PROTECTED]
> Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread)
> 
> I think they both use PostMessage and Control.Invoke waits on event.
> This difference is *almost* never makes a difference.
> 
> Dmitriy
> 
> Richard Blewett wrote:
> 
> >Control.Invoke uses SendMessage internally and Control.BeginInvoke uses
> >PostMessage.
> >
> >Regards
> >
> >Richard Blewett
> >DevelopMentor
> >
> >
> >
> >>-----Original Message-----
> >>From: Moderated discussion of advanced .NET topics. [mailto:ADVANCED-
> >>[EMAIL PROTECTED] On Behalf Of John Davis
> >>Sent: 01 March 2004 11:48
> >>To: [EMAIL PROTECTED]
> >>Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread)
> >>
> >>Yes, Control.Invoke uses the message pump.  The message pump is the
> queue
> >>you speak of.  I'm guessing the mechanism uses a PostMessage with a
> >>WM_USER
> >>+ x.
> >>
> >>----- Original Message -----
> >>From: "John Elliot" <[EMAIL PROTECTED]>
> >>To: <[EMAIL PROTECTED]>
> >>Sent: Monday, March 01, 2004 5:34 AM
> >>Subject: Re: [ADVANCED-DOTNET] Thread with message pump (UI thread)
> >>
> >>
> >>
> >>
> >>>>If the UI never accesses the model directly (which would require
> >>>>
> >>>>
> >>>locking
> >>>
> >>>
> >>>>to avoid possibly getting inconsistent data if the model is in the
> >>>>
> >>>>
> >>>process
> >>>
> >>>
> >>>>of being updated), but only sends requests (via BeginInvoke) to the
> >>>>
> >>>>
> >>>model
> >>>
> >>>
> >>>>thread for information, does that solve the problem?
> >>>>
> >>>>
> >>>I'm not sure that you can 'BeginInvoke onto the model thread'. As I
> >>>understand it (please correct me if I'm wrong), if I have a delegate I
> >>>can call BeginInvoke and it will be serviced by a worker thread from
> the
> >>>thread pool. I'm not sure that a 'worker thread from the thread pool'
> is
> >>>synonymous with 'model thread'.
> >>>
> >>>There are some gaps in my understanding around this however. For
> >>>example, how is it that Control.BeginInvoke allows the delegate to find
> >>>its way into the code path on the UI thread? The delegate must be added
> >>>to a queue and serviced at some point right? Which queue? Does it use
> >>>the message pump? If so, what sort of message does it send? Where can I
> >>>read about the mechanics of Control.BeginInvoke?
> >>>
> >>>The way I'm trying to think about it at the moment is that I have two
> >>>main threads. The 'UI thread' and the 'application thread'. The UI
> >>>serves two purposes:
> >>>
> >>>1. Represent the model (view)
> >>>2. Command the model (controller)
> >>>
> >>>My goal is to keep the UI as free as possible, basically the only
> >>>reasons for this are so that it can paint, respond to user requests
> that
> >>>don't rely on the model, or to 'cancel' something that is in progress.
> >>>It seems that a massive amount of work needs to be done to achieve
> these
> >>>relatively humble goals.
> >>>
> >>>The reason that this is hard in my particular case is that I have an
> MDI
> >>>WinForms application that shares data from a local (in-process) 'model'
> >>>of the data from the database. I don't use Dataset etc. because I run
> >>>into all sorts of trouble with a user fighting *with themself* over
> read
> >>>locks (i.e. timestamp/rowversion), defining complex relationships
> >>>between data that hasn't been allocated a primary key, etc. I use my
> own
> >>>business objects and collections to help me manage these relationships,
> >>>basically I'm building my own object-relational wrapper that is the
> main
> >>>component of the 'Model' in my MVC application.
> >>>
> >>>There are a few hairy design challenges. I want my model to be equally
> >>>usable in both a web based and WinForms based application. It gets
> >>>pretty challenging though, because the 'model' is designed for 'client
> >>>side' representation of data (I have a stateless application server
> that
> >>>can service requests and commands to populate the client-side model or
> >>>persist it to a data store) and these two execution contexts are quite
> >>>different.
> >>>
> >>>In a web based app, multiple users share a process, and if two users
> >>>were editing the same domain object (say, Employee, Invoice, etc.) then
> >>>I'd let them do it, and fail with an optimistic concurrency error ASAP
> >>>(to avoid them wasting their time). A web based app is largely
> >>>request-response, and so is simple in this regard. The user takes a
> read
> >>>lock (in the virtual, optimistic concurrency sense) on a 'smallish'
> >>>amount of data and then submits changes to that data, assuming there
> has
> >>>been no resource contention during the period that they were editing
> the
> >>>data I can just apply their changes, otherwise I can take them into a
> >>>'merge' process (heh, or fail them ;). Obviously, pessimistic
> >>>concurrency has a whole heap of problems (particularly with a web based
> >>>system) so I choose optimistic concurrency as the lessor of two evils.
> >>>
> >>>But an MDI WinForms app is quite different because it offers a more
> >>>sophisticated UI. In a windows based app, if I have the same domain
> >>>object open in two views, and I alter one view, then I don't want:
> >>>A. the other view to continue displaying stale data
> >>>B. the user to have a concurrency problem when they flip to the other
> >>>view later and make an edit (to the now stale data)
> >>>
> >>>I'd really like my business model to be resilient in the face of
> >>>'disconnection' too. So a user can carve off some existing data, enter
> >>>new data, specify complex relationships, and pump it all back into the
> >>>live system much later. I'd like to get as much support for this into
> >>>the business model (and related APIs) as possible, but this is largely
> >>>beside the point at the moment.
> >>>
> >>>I've already dealt with a lot of these problems, and I'm pretty happy
> >>>with what I've got (it's too complex for me to really go into via this
> >>>e-mail).
> >>>
> >>>I would describe what I have client-side in my MDI WinForms application
> >>>as an MVC application. I know that people argue about what MVC is, and
> >>>have different ideas about it. The scope of the problem that I'm trying
> >>>to describe here though, is that given this 'static' client-side model:
> >>>reading from it, updating it, etc. is all (relatively) straight forward
> >>>if all my processing happens synchronously on the UI thread. The
> problem
> >>>is that the UI thread is not free to respond to the user or paint
> itself
> >>>while it is processing, such processing pretty much always involves
> >>>going over the wire to the application server with blocking requests
> for
> >>>state or commands to change state (basically the CRUD).
> >>>
> >>>One of the particularly challenging problems is that 'View' code often
> >>>needs to do more than just 'read' from the model, often it needs to
> >>>'load' data into the model, and this is a long-running process.
> >>>Lazy-loading isn't an option if I don't want to block the UI thread,
> and
> >>>really is 'programming by side-effect', because I can affect the state
> >>>of the model by doing a read operation. Design challenges are further
> >>>aggravated by security, caching, etc.
> >>>
> >>>At the moment I'm really looking at how I can use a different kind of
> >>>messaging paradigm between the Model/View/Controller than I presently
> >>>have. At the moment such messages are passed using multicast delegates
> >>>(AKA events). The crux of the problem with this type of notification is
> >>>that the message is sent synchronously as it happens. So, I'm leaning
> >>>more towards a client/server type of messaging system (more like
> >>>publish/subscribe than 'observer' if it's fair to try and make such a
> >>>distinction) where I can queue the multicast delegate for invocation
> >>>later, rather than dispatch it immediately.
> >>>
> >>>What I'm finding is that I now need to maintain 'message and command
> >>>queues' that are serviced on the appropriate thread. For example, if
> >>>code executing on the 'application thread' causes a change in state to
> >>>the model that a view has registered interest in (by attaching an event
> >>>handler) then rather than synchronously invoking the event so the view
> >>>can be updated immediately, I'd like to place this event on a queue so
> >>>that once the processing on the 'application thread' runs to completion
> >>>and the model is returned to a 'consistent' and 'not-locked' state I
> can
> >>>dispatch all the messages on this queue on the UI thread and let the
> >>>View objects request the updated state from the appropriate parts of
> the
> >>>model (with no fear of the model either being locked or in an invalid
> >>>state). Interestingly, it seems that I also need a queue for queuing
> >>>long-running commands (like 'Save') triggered by the user (or an event)
> >>>on the UI thread for processing on the application thread. Then I need
> >>>some form of mutex that ensures that either the 'controller queue' is
> >>>being serviced XOR the 'view event queue' is being dispatched. Meaning
> >>>really that either the UI thread is reading from the model, or the
> >>>application thread is updating it, but neither can attempt to run at
> the
> >>>same time. On the face of it, this seems like the best way to go at the
> >>>moment, but perhaps this is a crazy idea?
> >>>
> >>>
> >>>
> >>>>The UI thread will update the display using information passed in
> >>>>
> >>>>
> >>>event-
> >>>
> >>>
> >>>>handler parameters (as you indicated was a possibility), or it can use
> >>>>BeginInvoke to send a request for model state to the model thread and
> >>>>
> >>>>
> >>>uses
> >>>
> >>>
> >>>>the results that (eventually) come back to update the display.  (The
> >>>>latter could happen if the user pressed a Refresh button, or expands a
> >>>>tree node whose contents only exist in the model, or some such.)  If
> >>>>
> >>>>
> >>>the
> >>>
> >>>
> >>>>user does something in the UI that should cause an update to the
> >>>>
> >>>>
> >>>model,
> >>>
> >>>
> >>>>the UI thread uses BeginInvoke to pass the "update model" request.
> >>>>
> >>>>
> >>>The 'pass state with event args' problem is interesting. Initially it
> >>>seems like this might be valid, but after a while you realise that (as
> >>>Shawn pointed out in his last post on this thread) you really need to
> >>>'clone' state objects that are not strictly 'atomic' or 'immutable'
> when
> >>>you do this. Once you start adding any degree of complexity, then this
> >>>can get completely out of control and you might have to clone thousands
> >>>of objects just so you could send a Client.ProjectChanged event. If it
> >>>was just Client.NameChanged I might be able to pass a string with the
> >>>new name in the event args, but if the 'property' that changed was a
> >>>related business object then I might have to clone it (and everything
> >>>that it contained) just to pass the event. If the UI then wanted data
> >>>from this cloned Project that had not yet been loaded, it would have to
> >>>query the application server for that data. Basically my entire goal is
> >>>to 'avoid cloning, at all, ever' on the client-side, because it can
> >>>really hurt the working set, but more particularly because once I clone
> >>>I have one user with duplicate read locks on the same data that they
> can
> >>>cause to become stale. My other goal is to 'avoid locking, at all,
> ever'
> >>>because saving myself from deadlocks is non-trivial, locking decreases
> >>>performance, and I can still end up blocking the UI thread. Usually the
> >>>solution to avoid one is to do the other, but I don't want to do
> either.
> >>>Like I said, I want to have my cake and eat it too! :)
> >>>
> >>>The only way that I can see to accomplish this, is to have a 'turn
> >>>based' system, where the UI thread has a go at reading changes,
> painting
> >>>itself and queuing commands, then the application thread has a go at
> >>>processing the command queue, updating the model and queuing
> >>>notifications for the UI. The UI can still do 'stuff' while the
> >>>application thread is executing, but it must guarantee not to touch the
> >>>model. I haven't hit the point where this gets unreasonable yet, but so
> >>>far it's only in my mind (no concept code or anything like that) so
> >>>there may be some complexity that this introduces that is beyond my
> >>>ability to address that I haven't stumbled across yet (if there is, it
> >>>will most likely be with the 'controller' side of the problem, because
> I
> >>>haven't had a close look into that yet).
> >>>
> >>>The reason that I need a 'client-side' model is that I don't want
> >>>'temporary state' to be maintained on behalf of clients by the
> >>>application server. Say I have a scenario where I'm entering a new
> >>>'Employee'. I client the 'Create new Employee' button, and up pops a
> >>>form. Behind the scenes there some code specified 'new Employee();' as
> >>>the data source on this form. The user enters the name etc, but wants
> to
> >>>add an 'Address' for the residential address. Given that the
> residential
> >>>address is now not going to be 'null' I create a 'new Address();' and
> >>>assign it. Now I'm starting to have complex 'temporary state' in the
> >>>client that will need to be persisted by the application server inside
> a
> >>>single transaction. If I then specified that this employees postal
> >>>address 'was the same as their residential address' I might do
> something
> >>>like this: this.Employee.PostalAddress =
> >>>this.Employee.ResidentialAddress; Now things are getting even tougher,
> >>>because not only have I got complex relationships that I need to model
> >>>without primary keys that will later be specified by application server
> >>>(or the database) but I also have to represent this change to the user
> >>>in the user interface. So, if I had two 'AddressControl' instances that
> >>>represented the Residential and Postal address for this Employee on the
> >>>'EmployeeControl' then if I changed the residential address I'd want to
> >>>see this change reflected in the postal address control. This is a
> >>>simple (and perhaps silly example) but it outlines the complexity that
> >>>I'm trying to model, and should serve to demonstrate why I can't
> >>>maintain the 'model' on the application server as easily as I can on
> the
> >>>client.
> >>>
> >>>Anyway, that's my rant for the day. At the end of the day the way I
> look
> >>>at it is that the MVC pattern (or perhaps I should say 'observer' or
> the
> >>>event-driven paradigm) is as old as time, async programming is as old
> as
> >>>time, and what I want is some good material where someone discusses
> >>>methods of integrating the concepts of each. I don't really want
> >>>asynchronous execution, what I really want is a method of keeping my UI
> >>>responsive while I work on shared local data, it's just that async
> >>>programming seems to be what I need to do to achieve this end. That's
> >>>way I'm happy to simply have the 'two main threads' and just managed
> >>>requests and notifications via queues. Obviously, in trying to do this,
> >>>a whole lot of things need to be taken into consideration, and
> >>>responsibilities and contracts need to be given to various components,
> >>>I'm trying to figure out what those should be, but if someone has
> >>>already done the work, I'd rather save myself some trouble.. :P
> >>>
> >>>Perhaps I should get myself a book on 'game programming'. Those guys
> >>>have been doing stuff like this for years right?
> >>>
> >>>The facilities in .NET alone at the moment are not of themselves
> >>>sophisticated enough to allow me to do everything that I want to do, so
> >>>I really need an application framework on top of .NET to help me.
> >>>
> >>>Obviously there are applications that work this way. Consider how
> VS.NET
> >>>works. If I have a class open in the code editor and change the class's
> >>>name, then the name change is reflected in the drop-down list on the
> >>>top, left and in the Class View. There is a slight delay in the UI
> being
> >>>updated however, and my keystrokes aren't delayed while the UI updates
> >>>itself (I think, I could be wrong about that), indicating that this
> >>>'event' has been queued and dispatched. Basically I want to know about
> a
> >>>pattern for accomplishing functionality like that. Is it simply the
> case
> >>>that they are using WM_PAINT, and invalidating the control? If so, then
> >>>what is the UI thread going to do when it wants the current value for
> >>>the class name? Lock the business model of the Class so that it can
> read
> >>>out the name value, meaning that the code editor needs to acquire the
> >>>same lock when updating? I'm sure that because of all the parsing, etc
> >>>that would be required this software is *far* more sophisticated that
> >>>what I'm trying to achieve, but there are elements of a similar pattern
> >>>that must have been addressed here right? If I was to run a 'find and
> >>>replace' operation, then I wouldn't want my code to alter the code
> >>>editors text box, but rather the 'compile unit' or 'source file'
> >>>business object, then have the changes reflected in the text box (the
> >>>view). My system is not a text editor of course; it's basically a
> >>>glorified database browser.
> >>>
> >>>Should I just give in and leave all my code on the UI thread? The
> >>>reality is that in a 'typical' usage scenario the UI locks up for much
> >>>less than 500ms during an operation, but this still sucks right? In my
> >>>travels I've never seen any software adequately deal with all of these
> >>>problems.
> >>>
> >>>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
> >>
> >>===================================
> >>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
> >>
> >>---
> >>Incoming mail is certified Virus Free.
> >>Checked by AVG anti-virus system (http://www.grisoft.com).
> >>Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
> >>
> >>
> >>
> >
> >---
> >Outgoing mail is certified Virus Free.
> >Checked by AVG anti-virus system (http://www.grisoft.com).
> >Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
> >
> >
> >===================================
> >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
> >
> >
> >
> 
> 
> ===================================
> 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
> 
> ---
> Incoming mail is certified Virus Free.
> Checked by AVG anti-virus system (http://www.grisoft.com).
> Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
> 

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
 

===================================
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