I've always thought of the user interface process of being just that ---
a single process. At least it would act that way, even if the VM was using some slight of hand to pull off some tricks. I basically thought, that if one didn't use "fork" in your application, that you didn't have to worry about concurrent access issues. I found a case where this breaks down when using a MessageBox. A distillation of the key methods is: MyPresenter>>myButtonWasClicked (MessageBox confirm: 'OK to do that?') ifTrue: [self doOperationWhichAlsoClearsTheCachedUIData]. MyImageView>>onPaintRequired: aPaintEvent self setImageByBuildingTheCacheOfUIData. ^super onPaintRequired: aPaintEvent I hadn't put any mutex's on the cached data, because I thought of the UI as being single threaded. But MessageBox>>basicOpen does a "Processor forkMainIfMain". The net result is that two different processes can be building and clearing the cache of UI data at the same time. The process building the data can, midway through its operation, suddenly find things have been nil'ed out by the other process. I see that using DialogViews with #showModal, is also forking the UI process. But in DialogView>>runModalLoop it is incrementing the priority of the process, if it had been the main process. The comment says: "Boost the initiating UI processes priority so that the operation requested by the user completes more quickly when the dialog is closed." It seems like the net effect would be that the code following the modal dialog would run without being interrupted by the (now lower priority) main UI process working on things from Windows input queue. Does the event that terminates the modal dialog come through Windows input queue? If so, then the main UI process would presumably not be in the middle of something else when the higher priority code after the dialog kicks in. If this analysis is accurate (please comment if you know), then overall, it still acts as if the UI was a single process. Is that right? I tried the same priority boosting trick in MessageBox>>basicOpen after the #forkMainIfMain. And my particular problem went away. Is this a recommended change to make? Should it be included in the base? thanks, -Bill ------------------------------------------- Bill Dargel [hidden email] Shoshana Technologies 100 West Joy Road, Ann Arbor, MI 48105 USA |
Bill
You wrote in message news:[hidden email]... > I've always thought of the user interface process of being just that --- > a single process. At least it would act that way, even if the VM was > using some slight of hand to pull off some tricks. I basically thought, > that if one didn't use "fork" in your application, that you didn't have > to worry about concurrent access issues. I found a case where this > breaks down when using a MessageBox. > [...snip...] > I hadn't put any mutex's on the cached data, because I thought of the UI > as being single threaded. But MessageBox>>basicOpen does a "Processor > forkMainIfMain". Yes this is one of the less satisfactory aspects of the way Dolphin manages multiple top-level native windows on a single OS thread, yet still maintaining correct (synchronous) behavior in the handling of messages, and permitting multiple modal dialogs. Ideally one would have one native OS thread per top-level Window, since this is the way Windows is designed to work - when a modal dialog is opened, the calling thread will usually disable the owner window and then go into a "local" message loop to service the dialog. This works fine for the thread-per-window model, as other UI threads can continue to service their associated windows without being affectged. If however there is only a single UI thread, then one can really only permit a single modal dialog to be opened when using a modal message loop. To see what I mean, try the following: 1) Modify the DialogView>>showModalTo: class to send #runModalInProcessLoop in place of #runModalLoop 2) Open a class browser, and bring up the find class prompter 3) Do the same with another class browser 4) Go back to the first class browser and prompter, and type in a class name to search for, save View, press Enter to close the dialog, noting that nothing happens! 5) Now go back to the second class browser, and search for another class. Note that when the second dialog is dismissed, the first browser eventually gets to complete the find operation. Essentially what this demonstrates is that the dialogs can't really be closed out of order if a modal in-process message loop is used, and hence the illusion of multiple independent top-level windows is lost. Other alternatives are even more unsatisfactory, for example: 1) Permit only a single modal dialog at a time. I think this would be pretty poor - and in fact it was, since this was the way some of the very early versions of Dolphin worked. 2) Implement an architecture with multiple "green" UI threads, one per top-level Window, dequeueing messages from the real Windows message queue, and pushing them off onto the internal queues of the green UI threads. This seems like a neat solution, but in fact if one does this, then one can never really get correct Windows behaviour, since a significant proportion of Windows messages are supposed to be handled synchronously - that is further events from the queue should not be retrieved and dispatched, until one has completed processing for those that occurred earlier. Handling the messages asynchronously would destroy any pretensions of tight (and correct) Win32 integration, and make it impossible to debug many things properly, or at all, at the Smalltalk level. So we're left with starting a new UI process when opening a modal dialog, and blocking the old one, and unfortunately this does mean that process synchronisation issues can arise unexpectedly. Where this is a problem with MessageBoxes, you have the option of flagging the MB as #taskModal. If you do this then it opens modal to all Windows, using a modal message loop, so a new UI process does not need to be started. Another technique is to make use of #queueDeferredAction: to push the processing back into the context of the (new) UI process. As an aside you may be wondering why, when the dialog is closed, the old UI process that was blocked when the dialog was opened, doesn't just reaassert itself over the new UI process. I can't quite remember the reason, so I will have to think about it. > .... > I see that using DialogViews with #showModal, is also forking the UI > process. But in DialogView>>runModalLoop it is incrementing the priority > of the process, if it had been the main process. The comment says: > "Boost the initiating UI processes priority so that the operation > requested by the user completes more quickly when the dialog is closed." > > It seems like the net effect would be that the code following the modal > dialog would run without being interrupted by the (now lower priority) > main UI process working on things from Windows input queue. Yes, that is the effect. Even if some other higher priority activity (e.g. a time firing) causes the processes to be rescheduled, Dolphin will always run the highest priority process that is ready to run, to the exclusion of any other lower priority processes. >...Does the > event that terminates the modal dialog come through Windows input queue? Yes.... > If so, then the main UI process would presumably not be in the middle of > something else when the higher priority code after the dialog kicks in. > If this analysis is accurate (please comment if you know), then overall, > it still acts as if the UI was a single process. Is that right? ...so the UI process does get blocked until the processing following the modal dialog completes, unless that processing should block due to waiting on a Mutex/Semaphore. > > I tried the same priority boosting trick in MessageBox>>basicOpen after > the #forkMainIfMain. And my particular problem went away. Is this a > recommended change to make? Should it be included in the base? Yes, I think it should. Its not ideal, but like I say, a pragmatic solution. Regards Blair |
Free forum by Nabble | Edit this page |