OO helps us with the complex issues of concurrency in the same way that is helps us with our "programming in the large" problems. Encapsulation, Abstraction, Inheritance all make it easier to isolate and re-use the solutions we come up with to our concurrency problems.
OO is certainly not a magic bullet for concurrency.
Booch distinguishes between active and inactive objects. Active objects are those with an independent thread of control that can execute in parallel with theads in other objects.
Look back at the ActiveTempSensor class. Walk through a messaging scenario:
- Function Creates TS –> TS Construction –> Function Messages TS –> TS Method Execution
We see how a TS can be messaged to do some work, but how can a temp sensor call anybody? Isn't there just a single thread of control? How does control transfer to the temp sensor so that it can message someone? Is the temp sensor a process?
The answer to these questions depends on the implementation. You might have a separate process for each temp sensor. You might have an event triggered by a hardware interrupt. You might have a multi-threaded app, with a separate thread for each sensor. You might have temp events come into the app with all the other events (mouse, keyboard, port events, etc). The answer depends on the OS environment.
The three sorts of solutions that are possible:
- a process abstraction from the OS
- a thread abstraction, within a single process
Synchronization is the big issue when you have concurrency.
Some terms help:
- Program: a collection of bytes on disk (passive, inactive)
- Process: living breathing entity which gets work done by executing a program
- Process space: where objects live; an address space
Processes with a single thread of control are easy to understand and follow. You can view their execution as follows:
The quiescent program starts execution within a method of the object receiving the "wakeup" event. This method in turn sends messages to other objects in the process space. They in turn may message other objects. Each of these messages eventually returns (with our without a value). Finally the first method to execute returns and the process is quiescent again.
Suppose you have a process with multiple threads of control. Now it is possible that an object is messaged at more or less the same time by two different objects. We need to worry about this concurrency. What does the messaged object promise the messaging objects? Three possibilities for synchronization:
- sequential - semantics of object are guaranteed only for one thread at a time (aka not thread safe)
- guarded - semantics of the object are guaranteed only if the threads coordinate with each other (i.e. synchronization is outside the object)
- synchronous - object guarantees its semantics by doing its own guarding
There is a range of time over which objects exist. From the most transitory (local variables within a method) to the most stable (objects that live forever). If an object is to have life beyond that of the process it runs in, some sort of db is needed.
The large investments in relational databases means that OO programmers often have to use an RDBMS to achieve a level of object persistence. This leads to the need for an object to know how to archive to and read itself from an RDBMS.
The up-and-coming alternative is an OO database. For storing/retrieving complex objects an OO db can be much faster than an RDB.
Some vendors of OODB: VERSANT, GemStone, ObjectStore, ONTOS. The RDB vendors (INGRES, Oracle) have announced intentions of extending or migrating to OO dbs.
The relational db model promotes a clean separation between the data and the logic or procedures for acting on the data. This helps you maintain stability and flexibility as requirements change. Since objects are all about wrapping data and functionality together, do we lose this advantage in an OODB? This trend can be seen in client/server database apps where triggers or stored procedures are part of the schema.