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!"