We have a racing condition in our program we can reproduce. Evaluate the
following: "open a tree view" treeModel := VirtualTreeModel new. treeModel getParentBlock: [:x | 0]; getChildrenBlock: [:x | Processor sleep: 100. "Allow the ex-Main process to run" #(1 2 3)]. treePresenter := TreePresenter showOn: treeModel. treePresenter view updateMode: #dynamic. "Change this to #static if you don't want GPF" "simulate a 'modal dialog' opening" Processor forkMainIfMain. "Now quickly change tree model twice" treeModel roots: #(0). Processor sleep: 50. "Allow the Main process to start painting with callbacks" treeModel roots: #(). You should see an "Invalid access to memory location". This occurs when you have two Smalltalk processes, that let each other to run AND changing the same TreeView. We have the following understanding of this case: 1) The ex-Main process (the process after forkMainIfMain) changes the tree model roots. A new tree view item is synchronously added to the tree control. 2) The ex-Main process waits and thereby allows the Main process to run. 3) The Main process receives a TVN_GETDISPINFO callback from the tree control and call among other things the getChildrenBlock, where it must wait. 4) As the Main process waits is the ex-Main process resumed. It changes the tree model roots again, so the TreeView sends the message TVM_DELETEITEM with TVI_ROOT. After that the ex-Main dies. 5) It's turn of the Main process now. It leaves the getChildrenBlock and finishes the callback... for an already deleted item! Tree view control crashes. To workaround the problem we've set the updateMode of the tree view to #static. What is the right solution of this problem? It's not so easy to remove all delays and semaphores in the both processes, because they are part of our business logic. Best Regards, Maxim Fridental |
"Maxim Fridental" <[hidden email]> wrote in message
news:bpqbal$1rmi6d$[hidden email]... > We have a racing condition in our program we can reproduce. Evaluate the > following: > > "open a tree view" >[...code snipped...] > > You should see an "Invalid access to memory location". This occurs when you > have two Smalltalk processes, that let each other to run AND changing the > same TreeView. We have the following understanding of this case: > 1) The ex-Main process (the process after forkMainIfMain) changes the tree > model roots. A new tree view item is synchronously added to the tree > control. > 2) The ex-Main process waits and thereby allows the Main process to run. > 3) The Main process receives a TVN_GETDISPINFO callback from the tree > control and call among other things the getChildrenBlock, where it must > wait. > 4) As the Main process waits is the ex-Main process resumed. It changes > tree model roots again, so the TreeView sends the message TVM_DELETEITEM > with TVI_ROOT. After that the ex-Main dies. > 5) It's turn of the Main process now. It leaves the getChildrenBlock and > finishes the callback... for an already deleted item! Tree view control > crashes. I would say your analysis is correct. The TreeView does not like its contents being changed while in the middle of a callback notification. The method comment of IconicListAbstract>>onLabelOf:editedTo: describes a situation where this has previously arisen (it also demonstrates our usual solution, more below). > > To workaround the problem we've set the updateMode of the tree view to > #static. What is the right solution of this problem? It's not so easy to > remove all delays and semaphores in the both processes, because they are > part of our business logic. Using #static is an option, but this is best reserved for cases where the internal model is unstable and one doesn't want the TreeView attempting to repaint the tree while the model is restructuring. It has the dowside of losing the ability to refresh the tree content merely by repainting it. Really what you need to do is to avoid updating the tree from anywhere but the main UI process. Dialogs can make this tricky. For further background on this search the newsgroup archived for the thread "User Interface single or multi threaded", initiated by Bill Dargel on 21 Feb 2003. My reply (which does not seem to be on Google Groups) explains the way dialogs are implemented and provides a design rationale. The easiest way to ensure that updates are done from the main UI process is to 'post' a block to the input queue to perform the actions taken after the dialog is closed. In this particular case you only need to post the final setting of the tree roots to prevent the GPF, so to get it working: .... [treeModel roots: #()] postToInputQueue However one should really post everything after the #forkMainIfMain. Another less intrusive (into the code anyway) solution is to modify DialogView to use #runModalInProcessLoop instead of #runModalLoop. This will, however, mean that you can no longer open more than one modal dialog at a time unless the dialogs are nested. This isn't an issue for many applications which have a single main window, though it is an unpleasant limitation in the multi-windowed Dolphin IDE. This approach could be employed quite neatly by creating a task modal (rather than view modal) subclass of DialogView that uses #runModalInProcessLoop, and then using that dialog view as the shell for the application's dialog view resources. Hope this helps Blair |
Could you please repost the thread (it is not on the google groups indeed).
"Blair McGlashan" <blair@no spam object-arts.com> schrieb im Newsbeitrag news:3fc36185$[hidden email]... > "Maxim Fridental" <[hidden email]> wrote in message > news:bpqbal$1rmi6d$[hidden email]... > > We have a racing condition in our program we can reproduce. Evaluate the > > following: > > > > "open a tree view" > >[...code snipped...] > > > > You should see an "Invalid access to memory location". This occurs when > you > > have two Smalltalk processes, that let each other to run AND changing > > same TreeView. We have the following understanding of this case: > > 1) The ex-Main process (the process after forkMainIfMain) changes the tree > > model roots. A new tree view item is synchronously added to the tree > > control. > > 2) The ex-Main process waits and thereby allows the Main process to run. > > 3) The Main process receives a TVN_GETDISPINFO callback from the tree > > control and call among other things the getChildrenBlock, where it must > > wait. > > 4) As the Main process waits is the ex-Main process resumed. It changes > the > > tree model roots again, so the TreeView sends the message TVM_DELETEITEM > > with TVI_ROOT. After that the ex-Main dies. > > 5) It's turn of the Main process now. It leaves the getChildrenBlock and > > finishes the callback... for an already deleted item! Tree view control > > crashes. > > I would say your analysis is correct. The TreeView does not like its > contents being changed while in the middle of a callback notification. The > method comment of IconicListAbstract>>onLabelOf:editedTo: describes a > situation where this has previously arisen (it also demonstrates our usual > solution, more below). > > > > > To workaround the problem we've set the updateMode of the tree view to > > #static. What is the right solution of this problem? It's not so easy to > > remove all delays and semaphores in the both processes, because they are > > part of our business logic. > > Using #static is an option, but this is best reserved for cases where the > internal model is unstable and one doesn't want the TreeView attempting to > repaint the tree while the model is restructuring. It has the dowside of > losing the ability to refresh the tree content merely by repainting it. > > Really what you need to do is to avoid updating the tree from anywhere but > the main UI process. Dialogs can make this tricky. For further background > this search the newsgroup archived for the thread "User Interface single or > multi threaded", initiated by Bill Dargel on 21 Feb 2003. My reply (which > does not seem to be on Google Groups) explains the way dialogs are > implemented and provides a design rationale. > > The easiest way to ensure that updates are done from the main UI process is > to 'post' a block to the input queue to perform the actions taken after the > dialog is closed. In this particular case you only need to post the final > setting of the tree roots to prevent the GPF, so to get it working: > > .... > [treeModel roots: #()] postToInputQueue > > However one should really post everything after the #forkMainIfMain. > > Another less intrusive (into the code anyway) solution is to modify > DialogView to use #runModalInProcessLoop instead of #runModalLoop. This > will, however, mean that you can no longer open more than one modal dialog > at a time unless the dialogs are nested. This isn't an issue for many > applications which have a single main window, though it is an unpleasant > limitation in the multi-windowed Dolphin IDE. This approach could be > employed quite neatly by creating a task modal (rather than view modal) > subclass of DialogView that uses #runModalInProcessLoop, and then using > dialog view as the shell for the application's dialog view resources. > > Hope this helps > > Blair > > |
Carsten,
> Could you please repost the thread (it is not on the google groups > indeed). If you go to http://www.idb.me.uk/news.html you can find the posts you want in the archive. You will need the Feb 2003 file (there are only two posts in the thread). -- Ian |
In reply to this post by Carsten Haerle
Blair,
> > Another less intrusive (into the code anyway) solution is to modify > > DialogView to use #runModalInProcessLoop instead of #runModalLoop. This > > will, however, mean that you can no longer open more than one modal dialog > > at a time unless the dialogs are nested. This isn't an issue for many > > applications which have a single main window, though it is an unpleasant > > limitation in the multi-windowed Dolphin IDE. This approach could be > > employed quite neatly by creating a task modal (rather than view modal) > > subclass of DialogView that uses #runModalInProcessLoop, and then using > that > > dialog view as the shell for the application's dialog view resources. Is that a decision that could be factored into a policy that can be set in a reasonable way? The first thing that comes to mind is to default to allowing independent modal dialogs, and let the session manager change the policy if it wants. Those having problems in the IDE would probably want additional control, but thanks to Smalltalk, they'd have it. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Bill
You wrote in message news:bqisbf$22k1f1$[hidden email]... > > > > Another less intrusive (into the code anyway) solution is to modify > > > DialogView to use #runModalInProcessLoop instead of #runModalLoop. This > > > will, however, mean that you can no longer open more than one modal > dialog > > > at a time unless the dialogs are nested. This isn't an issue for many > > > applications which have a single main window, though it is an unpleasant > > > limitation in the multi-windowed Dolphin IDE. This approach could be > > > employed quite neatly by creating a task modal (rather than view modal) > > > subclass of DialogView that uses #runModalInProcessLoop, and then using > > that > > > dialog view as the shell for the application's dialog view resources. > > Is that a decision that could be factored into a policy that can be set in a > reasonable way? The first thing that comes to mind is to default to > allowing independent modal dialogs, and let the session manager change the > policy if it wants. Those having problems in the IDE would probably want > additional control, but thanks to Smalltalk, they'd have it. I suppose that could be done, but that would introduce a difference in behaviour between development and runtime environments. I think it might be better to allow this to be specified on a per dialog basic, probably by having a flag that can be set in much the same way that one can specify task modal message boxes. Regards Blair |
Blair,
> I suppose that could be done, but that would introduce a difference in > behaviour between development and runtime environments. That's not necessarily all bad, since one will almost certainly want to switch to a different window and do something in the IDE, where many single-shell apps will not offer that option, and might benefit from the stricter/safer approach to modality. However... > I think it might be > better to allow this to be specified on a per dialog basic, probably by > having a flag that can be set in much the same way that one can specify task > modal message boxes. That sounds great! Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Free forum by Nabble | Edit this page |