Concurrent programming vs. concurrency control: shared events or shared data
Authors: Martin Bruce 
Published: November 2005

Two views of concurrency in an object system exist. Those pursuing
concurrent programming
believe that
activities
in the real world are inherently concurrent and therefore objects are themselves active. Objects engage in shared events by sending and receiving messages. Communicating Sequential Processes [Hoar85a] and Actors [Agha86a] embrace this view. On the other hand, those pursuing models of
concurrency control
believe that objects are
data
and that concurrent access to data needs to be controlled by the system according to some correctness notion. Database transactions, atomic objects [Weih84a, Schw84a] and nested objects [Mart88a] embrace this view.

Concurrent programming, in our view, places a significant burden on programming. Correct concurrent behavior is specified as combinations of interactions within a potentially large set of concurrent objects. A programmer must verify that the implementations of all the objects never produce undesirable interactions. Correctness of concurrent behavior is left to the programmer.

We are pursuing models embracing concurrency control primarily because a programmer is not required to consider concurrency. The operations on an object can be specified in terms of preconditions and postconditions and traditional program verification techniques can be used to verify an operation's implementation. A programmer only considers the serial behavior of an object in
isolation
; he need not concern himself with how other concurrent activities might affect the object. Correctness of interleavings is left to the system.

Serializability
is the usual correctness notion for concurrency control algorithms. In transaction terminology, each competing transaction executes a sequence of basic
actions
. Any interleaving of the actions is correct if it is equivalent to some serial execution of the transaction. Serializability allows a transaction to be programmed in isolation, that is without considering possible interleavings with other transactions. The system may indeed interleave the actions of several transactions but it is up to the system to make the interleaving appear serial.

Concurrent programming is apparently more general. A programmer can implement anything, including undesirable interactions like deadlock. The price for this generality is that the programmer must reason about global orderings of events and thus correctness is difficult to show.

The traditional transaction model is not general enough for programming shared object systems. For example, several researchers, [Bern87a, Garc87a, Pu88a], have recognized that transactions are too restrictive for long-lived activities. The problem is that the transaction model is too conservative. Only reading and writing a data item at a single layer of abstraction is modeled. Once a read-write, write-read or write-write dependency is established between two transactions, it remains for the life of the transaction and limits further interleavings.

Our approach is to discover and explore less restrictive correctness notions that still allow programmers to implement operations on objects in isolation. In [Mart88a] we present two such correctness notions:
externally serializable computations
and
semantically verifiable nonserializable computations
. Both correctness notions assume the nested object model. In [Mart87a] we give a nested object solution to the Dining Philosophers' Problem [Dijk71a]. Nested objects incorporate both the
semantics
of an object and the data abstraction
hierarchy
of an object.

Nested objects form a nested object system. A nested object system is hierarchical; objects exist at different levels of the system. The execution of an operation on an object at level
i
results in the execution of operations on objects at level
i-1
. However, only top level objects are viewed externally.

A computation at level
i
is a description of the state change made to level
i
objects and the return values produced by executing a partially ordered set of operations on level
i
objects. The computations at each level together form an
n
-level system computation.

Externally serializable computations are
n
-level system computations in which the top level objects are left in states that could be produced by serial computations. However, lower level objects may be left in states that no serial computation could produce. Because both data abstraction hierarchies and operations semantics are considered in the nested object model, dependencies established between concurrent computations can be systematically ignored. Long-lived computations can execute efficiently if dependencies can later be ignored.

Nested objects are more general than other models of concurrency control. Transactions are two-level nested objects that read and write basic data items. Atomic objects are two-level nested objects that perform abstract operations.

The 1988 Object Based Concurrent Programming Workshop did not directly address the differences between concurrent programming and concurrency control. Perhaps future workshops can contrast the generality, the applicability, the programmability, the security and the performance implications of models from both concurrent programming and concurrency control.