> 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