Re: Synchronization questions
Andreas L. Delmelle wrote: -Original Message- From: Peter B. West [mailto:[EMAIL PROTECTED] I've been hacking the tree methods in Node recently ... Are you talking 'maintenance vs. HEAD' here? No. I realise the message was ambiguous. I was talking about versions of my general tree-handling classes - Node (primarily) and Tree. My first change was to synchronize the methods which had previously been synchronized on the Tree, but I realized that such synchronization of methods in inner classes probably only synchronized on the actual inner class instance, not on the containing class instance. Does anyone have any knowledge of this? Hmm... Difficult to tell from the docs I read, so far... I'd say: indeed, unless the code-block through which the inner class (synchronized) method is accessed is synchronized on the containing class instance, no? Then again, synchronizing only on the inner classes could turn out to offer more flexibility, as other operations on the containing class can still be carried out while the inner class is locked (provided, of course, that the 'other' operations do not need access to the inner class instance...) In this case they do need such access. The inner classes are iterators. It also occurred to me that optional synchronization might be a good idea, allowing a common synchronization object to be passed to the Node constructor. An alternative was to allow optional synchronization, but to synchronize on the affected Node object. On the construction of any particular Node, a boolean can be passed indicating the need for synchronization. The other solution for the above stated issue: remove the synchronization from the inner class methods, and synchronize their bodies on the containing class instance. (Again: IIC you'd only need this if you really *need* to synchronize on the outer class... if you don't, I guess the approach you're taking now is more flexible and less likely to lead to deadlocks.) I was worried about increasing the probability of deadlock by having many more locks held concurrently. Without having thought about it a great deal, it seems to me that it is easier to appreciate and avoid potential deadlocks when synchronization is more global, as with the synchronization on the containing Tree object. snip / Does anyone have experience with such issues? No real experience, but thinking about 'optional synchronization' brings up all sorts of ideas, like: - a Lockable interface for Nodes - a SyncedNode extending Node implementing the Lockable interface - when you really only need a non- or partly synchronized Node use the main type; if you need a fully synchronized one, use the subtype (ratio of execution speeds from non-synced vs. synced is roughly 100 vs. 150, so it would definitely be worth it to avoid synchronization altogether where it is not strictly necessary) This would be the clean way to express the current version of the code. However, I am still toying with the idea of allowing (sub)trees to synchronize on an object passed in as a parameter to the Node constructor. If the object reference is null, synchronization is turned off. In this scheme, I would allow subclasses (like Area) to switch synchronization on by setting the 'sync' object non-null, as, for example, when a locally constructed subtree was grafted onto the AreaTree. It also returns to the situation of a common synchronization object for each node in the (sub)tree. Peter -- Peter B. West http://www.powerup.com.au/~pbwest/resume.html
Re: Synchronization questions
Peter B. West wrote: This would be the clean way to express the current version of the code. However, I am still toying with the idea of allowing (sub)trees to synchronize on an object passed in as a parameter to the Node constructor. If the object reference is null, synchronization is turned off. In this scheme, I would allow subclasses (like Area) to switch synchronization on by setting the 'sync' object non-null, as, for example, when a locally constructed subtree was grafted onto the AreaTree. It also returns to the situation of a common synchronization object for each node in the (sub)tree. The notion of switching synchronization on and off is, unfortunately, brain-dead. If synchronization is to be changed, then the code which changes and reads the synchronization state must itself be synchronized. The conditional synchronization that I have now is only workable because the setting for any particular node is immutable. Peter -- Peter B. West http://www.powerup.com.au/~pbwest/resume.html
RE: Synchronization questions
-Original Message- From: Peter B. West [mailto:[EMAIL PROTECTED] snip / It also occurred to me that optional synchronization might be a good idea, allowing a common synchronization object to be passed to the Node constructor. An alternative was to allow optional synchronization, but to synchronize on the affected Node object. On the construction of any particular Node, a boolean can be passed indicating the need for synchronization. [Me :] The other solution for the above stated issue: remove the synchronization from the inner class methods, and synchronize their bodies on the containing class instance. (Again: IIC you'd only need this if you really *need* to synchronize on the outer class... if you don't, I guess the approach you're taking now is more flexible and less likely to lead to deadlocks.) I was worried about increasing the probability of deadlock by having many more locks held concurrently. Without having thought about it a great deal, it seems to me that it is easier to appreciate and avoid potential deadlocks when synchronization is more global, as with the synchronization on the containing Tree object. Yes, I see what you mean... Well, as I indicated, there's absolutely no reason to trust me on this. Your view is probably more to the point here. The only thing I do know for sure is that many authors claim that most possible cases of deadlock can --and should preferrably be - identified in advance (i.e. before any code is ever written). The two most common cases of deadlock are AFAIK: 1. A thread that doesn't exit (cleanly), so never releases the lock (threads going into an infinite loop belong to this category) 2. Two threads 'waiting for each other': one holding the lock and waiting for a return value from the second, the other needing access to the locked object in order to return the desired value. So it would come down to predicting in some way the risk of either of these two taking place. I guess that, when synchronization is more global, the first type would be easier to avoid. Mostly, it's also advised not to synchronize *every* method, actually leaving a backdoor opened to be able to cleanly open the lock from the inside (--but I'm guessing this is well-known fact to you). This would be an argument against all-too-eagerly-global synchronization IMHO. (On top of that, but this may be a consequence of the limitation of my understanding of the FO process in its entirety, it seemed easier to me to avoid the first cases manually and the second by design, than doing it the other way around. I'm still not completely familiar with the 'borderline' cases, where an event downstream would influence upstream events in such a way that they might need access to a Node on which a lock is being held by another process...) snip / However, I am still toying with the idea of allowing (sub)trees to synchronize on an object passed in as a parameter to the Node constructor. If the object reference is null, synchronization is turned off. In this scheme, I would allow subclasses (like Area) to switch synchronization on by setting the 'sync' object non-null, as, for example, when a locally constructed subtree was grafted onto the AreaTree. It also returns to the situation of a common synchronization object for each node in the (sub)tree. [Your follow-up: ] The notion of switching synchronization on and off is, unfortunately, brain-dead. If synchronization is to be changed, then the code which changes and reads the synchronization state must itself be synchronized. The conditional synchronization that I have now is only workable because the setting for any particular node is immutable. And so if you need a non-synched version of the same Node, you would need to create a non-synched clone/copy (--preferrably disposable)? Cheers, Andreas
Re: Synchronization questions
Andreas L. Delmelle wrote: -Original Message- From: Peter B. West [mailto:[EMAIL PROTECTED] ... I was worried about increasing the probability of deadlock by having many more locks held concurrently. Without having thought about it a great deal, it seems to me that it is easier to appreciate and avoid potential deadlocks when synchronization is more global, as with the synchronization on the containing Tree object. Yes, I see what you mean... Well, as I indicated, there's absolutely no reason to trust me on this. Your view is probably more to the point here. The only thing I do know for sure is that many authors claim that most possible cases of deadlock can --and should preferrably be - identified in advance (i.e. before any code is ever written). The two most common cases of deadlock are AFAIK: 1. A thread that doesn't exit (cleanly), so never releases the lock (threads going into an infinite loop belong to this category) This is always going to be tricky. 2. Two threads 'waiting for each other': one holding the lock and waiting for a return value from the second, the other needing access to the locked object in order to return the desired value. See comments below. So it would come down to predicting in some way the risk of either of these two taking place. I guess that, when synchronization is more global, the first type would be easier to avoid. Mostly, it's also advised not to synchronize *every* method, actually leaving a backdoor opened to be able to cleanly open the lock from the inside (--but I'm guessing this is well-known fact to you). This would be an argument against all-too-eagerly-global synchronization IMHO. It's only necessary to synchronize the methods that read or modify the data that is in contention. I suspect that a lot of synchronized code is written by those who don't quite understand why, and who take the first approach that seems to work. I get the feeling that quick and easy approaches are frequently encouraged. (On top of that, but this may be a consequence of the limitation of my understanding of the FO process in its entirety, it seemed easier to me to avoid the first cases manually and the second by design, than doing it the other way around. I'm still not completely familiar with the 'borderline' cases, where an event downstream would influence upstream events in such a way that they might need access to a Node on which a lock is being held by another process...) Deadlock problems have to be considered carefully at the design stage. In my original considerations for the pipelined model of alt-design, I was happy to have blocking writes/reads on the buffers of the primary pipeline (parser-fo tree builder-area tree builder), but I thought there would be deadlock problems if the return message queues were blocking. (See figure 3 - incorrectly captioned Figure 2 - of http://xml.apache.org/fop/design/alt.design/xml-parsing.html). I believe that the less complicated the synchronization structure, the easier it will be to analyse the possibilities for deadlock, hence my interest in getting back to more global synchronization objects. snip / However, I am still toying with the idea of allowing (sub)trees to synchronize on an object passed in as a parameter to the Node constructor. If the object reference is null, synchronization is turned off. In this scheme, I would allow subclasses (like Area) to switch synchronization on by setting the 'sync' object non-null, as, for example, when a locally constructed subtree was grafted onto the AreaTree. It also returns to the situation of a common synchronization object for each node in the (sub)tree. [Your follow-up: ] The notion of switching synchronization on and off is, unfortunately, brain-dead. If synchronization is to be changed, then the code which changes and reads the synchronization state must itself be synchronized. The conditional synchronization that I have now is only workable because the setting for any particular node is immutable. And so if you need a non-synched version of the same Node, you would need to create a non-synched clone/copy (--preferrably disposable)? It seems to be the only way to do it. Peter -- Peter B. West http://www.powerup.com.au/~pbwest/resume.html
RE: Synchronization questions
-Original Message- From: Peter B. West [mailto:[EMAIL PROTECTED] I've been hacking the tree methods in Node recently, triggered by the need to construct multiple subtrees during area tree construction, cobbling them together as necessary. In the original version, I was able to synchronize on the Node's containing Tree instance, but that is no longer feasible, as Nodes may be free-floating. Are you talking 'maintenance vs. HEAD' here? My first change was to synchronize the methods which had previously been synchronized on the Tree, but I realized that such synchronization of methods in inner classes probably only synchronized on the actual inner class instance, not on the containing class instance. Does anyone have any knowledge of this? Hmm... Difficult to tell from the docs I read, so far... I'd say: indeed, unless the code-block through which the inner class (synchronized) method is accessed is synchronized on the containing class instance, no? Then again, synchronizing only on the inner classes could turn out to offer more flexibility, as other operations on the containing class can still be carried out while the inner class is locked (provided, of course, that the 'other' operations do not need access to the inner class instance...) It also occurred to me that optional synchronization might be a good idea, allowing a common synchronization object to be passed to the Node constructor. An alternative was to allow optional synchronization, but to synchronize on the affected Node object. On the construction of any particular Node, a boolean can be passed indicating the need for synchronization. The other solution for the above stated issue: remove the synchronization from the inner class methods, and synchronize their bodies on the containing class instance. (Again: IIC you'd only need this if you really *need* to synchronize on the outer class... if you don't, I guess the approach you're taking now is more flexible and less likely to lead to deadlocks.) snip / Does anyone have experience with such issues? No real experience, but thinking about 'optional synchronization' brings up all sorts of ideas, like: - a Lockable interface for Nodes - a SyncedNode extending Node implementing the Lockable interface - when you really only need a non- or partly synchronized Node use the main type; if you need a fully synchronized one, use the subtype (ratio of execution speeds from non-synced vs. synced is roughly 100 vs. 150, so it would definitely be worth it to avoid synchronization altogether where it is not strictly necessary) Then again, perhaps even too little experience to be able to tell the exact (dis)advantages of this idea, so feel free to point out any errors in logic... Cheers, Andreas