matt@bacchus.esa.oz.au (Matthew Atterbury) (04/09/91)
Hi all, I would like to hear people's thoughts on concurrency and how it relates to this new-fangled object oriented stuff :-). First, a quick explanation of where I'm coming from: We develop multi-user graphics oriented software (e.g. train control systems, airline scheduling systems). There are multiple users who are all working on a global pool of data, although usually this is partitioned operationally (e.g. usually one Train Controller [TC] looks after a physical area, and trains are 'handed over' between TCs at the dividing line). However, there are definite times when the same data may be manipulated by different people. Now, we have a "database" system (well, file system really) which helps handle the concurrency control: replicated data servers, one of which is the `master'; to make a change to the global data (i.e. the copies of the data on all servers) you submit a delta (basically a change request) to the master who verifies it, and if it is OK, applies and distributes it to all the other servers. This works well, and I don't need help there, although someone may have ideas about how the concurrency control can be better achieved (I do not consider locking a 'better' solution). In general, users want to be able to 'play with' their copy of the data whilst retaining the ability to either commit or abort what they're doing (e.g. a scheduler may want to manipulate today's schedule to see if s/he can fix some problem, but if it doesn't, they just undo what they've done). With delta's, this is pretty easy: you just slowly build up a delta of their changes which you eventually commit or discard. So, what's the problem? Well, ... 1) None of the above is particularly object oriented (although it is in lotsa ways), mainly because the delta consists of things like "change bytes 20 - 23 of record 1234 to 0x12345678". I don't know of any better way of describing the delta without it having to have semantic knowledge of the objects. 2) There seems little/no language support for such concurrency issues in main-stream OO languages (I consider C++ and Eiffel as the 'mainest-stream' languages available). Now it may be that the answer to all my problems is LOOPS / CLOS / Flavors / Actor / Smalltalk-91 / whatever, but moving to such a language has real problems, although I would certainly look at it to see how it can solve my problem(s). 3) There seems little/no language support for degrees of object persistence, which is part of my problem. Hiding from the class client the fact that the class is also saved in some database is not easy in C++/Eiffel, at least because you've got to know internal junk about the object. Compare this with Smalltalk/V which (as far as I remember!) automatically pages objects in/out of memory for you. Sure, it doesn't handle concurrency, but it's a start. The best answer I have come up so far is for each updating method in a concurrent class's interface to take a delta as an argument, and as well as updating the local copy of the updated object, it also adds the necessary changes to the delta. This delta is later committed or discarded as the user wishes. Pros - The local data can be backtracked to its global value if the delta is discarded (or the commit fails). - Global data changes (i.e. from OTHER users) can be compared with the delta to predict that the delta will fail if committed (i.e. because someone else has made a conflicting change). - Multiple deltas can be managed, allowing any object to participate in multiple 'what-if' scenario's (e.g. say each method simply added the changes to some global delta - we would have the above Pros, but we could have only one 'what-if' at a time). Cons - The class client HAS to know that it is a concurrent class because it is has to pass the delta in. I see this as a big problem. as I would like the application programmer to be able to use all classes uniformly, without having to keep track themself which classes are concurrent and which aren't (is this reasonable?). A possibly better solution may be a 'global' delta thread which the application programmer has to set at the start of any operation, and which concurrent modules interrogate to find the delta to add their change to. e.g. (sorry, it's C'ish) /* utility function which handles the user editing a leg of a trip */ edit_leg (Delta theDelta, Leg theLeg) { : set_current_thread(theDelta); : leg_muck_about(theLeg); : set_current_thread((Delta) NULL); : } /* method of the Leg module which updates some part of a Leg */ leg_muck_about(Leg theLeg) { Delta theDelta; : theDelta = get_current_thread(); : delta_change_field(theDelta, /* add change to delta */ theLeg, offsetof(Leg, field), sizeof(Leg, field), theLeg->field, value); theLeg->field = value; : } Personally, I would like us to move over to Eiffel, but any language we move to would have to allow us to handle persistent concurrent objects "relatively" easily. Has anyone else done any thinking on these issues? -- ------------------------------------------------------------------------------- Matt Atterbury [matt@bacchus.esa.oz.au] Expert Solutions Australia, Melbourne UUCP: ...!uunet!munnari!matt@bacchus.esa.oz.au "klaatu barada nikto" ARPA: matt%bacchus.esa.oz.AU@uunet.UU.NET "life? don't talk to me about life!"