Time, Clocks, and the Ordering of Events in a Distributed System

About this paperTiếng Việt中文日本語beside Tiếng Việtbeside 中文beside 日本語

This paper is under a licence that does not allow it to be reproduced, so what is here is its front matter and a short abstract. Read it at the publisher's page.

The concept of one event happening before another in a distributed system is examined, and is shown to define a partial ordering of the events. A distributed algorithm is given for synchronizing a system of logical clocks which can be used to totally order the events. The use of the total ordering is illustrated with a method for solving synchronization problems. The algorithm is then specialized for synchronizing physical clocks, and a bound is derived on how far out of synchrony the clocks can become.

Key Words and Phrases: distributed systems, computer networks, clock synchronization, multiprocess systems

CR Categories: 4.32, 5.29

Introduction

The concept of time is fundamental to our way of thinking. It is derived from the more basic concept of the order in which events occur. We say that something happened at 3:15 if it occurred after our clock read 3:15 and before it read 3:16. The concept of the temporal ordering of events pervades our thinking about systems. For example, in an airline reservation system we specify that a request for a reservation should be granted if it is made before the flight is filled. However, we will see that this concept must be carefully reexamined when considering events in a distributed system.

A distributed system consists of a collection of distinct processes which are spatially separated, and which communicate with one another by exchanging messages. A network of interconnected computers, such as the ARPA net, is a distributed system. A single computer can also be viewed as a distributed system in which the central control unit, the memory units, and the input-output channels are separate processes. A system is distributed if the message transmission delay is not negligible compared to the time between events in a single process.

We will concern ourselves primarily with systems of spatially separated computers. However, many of our remarks will apply more generally. In particular, a multiprocessing system on a single computer involves problems similar to those of a distributed system because of the unpredictable order in which certain events can occur.

In a distributed system, it is sometimes impossible to say that one of two events occurred first. The relation "happened before" is therefore only a partial ordering of the events in the system. We have found that problems often arise because people are not fully aware of this fact and its implications.

In this paper, we discuss the partial ordering defined by the "happened before" relation, and give a distributed algorithm for extending it to a consistent total ordering of all the events. This algorithm can provide a useful mechanism for implementing a distributed system. We illustrate its use with a simple method for solving synchronization problems. Unexpected, anomalous behavior can occur if the ordering obtained by this algorithm differs from that perceived by the user. This can be avoided by introducing real, physical clocks. We describe a simple method for synchronizing these clocks, and derive an upper bound on how far out of synchrony they can drift.

The Partial Ordering

Most people would probably say that an event aa happened before an event bb if aa happened at an earlier time than bb. They might justify this definition in terms of physical theories of time. However, if a system is to meet a specification correctly, then that specification must be given in terms of events observable within the system. If the specification is in terms of physical time, then the system must contain real clocks. Even if it does contain real clocks, there is still the problem that such clocks are not perfectly accurate and do not keep precise physical time. We will therefore define the "happened before" relation without using physical clocks.

We begin by defining our system more precisely. We assume that the system is composed of a collection of processes. Each process consists of a sequence of events. Depending upon the application, the execution of a subprogram on a computer could be one event, or the execution of a single machine instruction could be one

Figure.

Fig. 2.

Figure.

event. We are assuming that the events of a process form a sequence, where aa occurs before bb in this sequence if aa happens before bb. In other words, a single process is defined to be a set of events with an a priori total ordering. This seems to be what is generally meant by a process.1^1 It would be trivial to extend our definition to allow a process to split into distinct subprocesses, but we will not bother to do so.

We assume that sending or receiving a message is an event in a process. We can then define the “happened before” relation, denoted by “→\rightarrow,” as follows.

Definition. The relation “→\rightarrow” on the set of events of a system is the smallest relation satisfying the following three conditions: (1) If aa and bb are events in the same process, and aa comes before bb, then a→ba \rightarrow b. (2) If aa is the sending of a message by one process and bb is the receipt of the same message by another process, then a→ba \rightarrow b. (3) If a→ba \rightarrow b and b→cb \rightarrow c then a→ca \rightarrow c. Two distinct events aa and bb are said to be concurrent if a↛ba \not\rightarrow b and b↛ab \not\rightarrow a.

We assume that a↛aa \not\rightarrow a for any event aa. (Systems in which an event can happen before itself do not seem to be physically meaningful.) This implies that →\rightarrow is an irreflexive partial ordering on the set of all events in the system.

It is helpful to view this definition in terms of a “space-time diagram” such as Figure 1. The horizontal direction represents space, and the vertical direction represents time—later times being higher than earlier ones. The dots denote events, the vertical lines denote processes, and the wavy lines denote messages.2^2 It is easy to see that a→ba \rightarrow b means that one can go from aa to bb in the diagram by moving forward in time along process and message lines. For example, we have p1→r4p_1 \rightarrow r_4 in Figure 1.

Another way of viewing the definition is to say that a→ba \rightarrow b means that it is possible for event aa to causally affect event bb. Two events are concurrent if neither can causally affect the other. For example, events p3p_3 and q3q_3 of Figure 1 are concurrent. Even though we have drawn the diagram to imply that q3q_3 occurs at an earlier physical time than p3p_3, process P cannot know what process Q did at q3q_3 until it receives the message at p4p_4. (Before event p4p_4, P could at most know what Q was planning to do at q3q_3.)

This definition will appear quite natural to the reader familiar with the invariant space-time formulation of special relativity, as described for example in [1] or the first chapter of [2]. In relativity, the ordering of events is defined in terms of messages that could be sent. However, we have taken the more pragmatic approach of only considering messages that actually are sent. We should be able to determine if a system performed correctly by knowing only those events which did occur, without knowing which events could have occurred.

Logical Clocks

We now introduce clocks into the system. We begin with an abstract point of view in which a clock is just a way of assigning a number to an event, where the number is thought of as the time at which the event occurred. More precisely, we define a clock CiC_i for each process PiP_i to be a function which assigns a number Ci(a)C_i(a) to any event aa in that process. The entire system of clocks is represented by the function C which assigns to any event bb the number C(b)C(b), where C(b)=Cj(b)C(b) = C_j(b) if bb is an event in process PjP_j. For now, we make no assumption about the relation of the numbers Ci(a)C_i(a) to physical time, so we can think of the clocks CiC_i as logical rather than physical clocks. They may be implemented by counters with no actual timing mechanism.

1^1 The choice of what constitutes an event affects the ordering of events in a process. For example, the receipt of a message might denote the setting of an interrupt bit in a computer, or the execution of a subprogram to handle that interrupt. Since interrupts need not be handled in the order that they occur, this choice will affect the ordering of a process’ message-receiving events.

2^2 Observe that messages may be received out of order. We allow the sending of several messages to be a single event, but for convenience we will assume that the receipt of a single message does not coincide with the sending or receipt of any other message.

Figure.

We now consider what it means for such a system of clocks to be correct. We cannot base our definition of correctness on physical time, since that would require introducing clocks which keep physical time. Our definition must be based on the order in which events occur. The strongest reasonable condition is that if an event aa occurs before another event bb, then aa should happen at an earlier time than bb. We state this condition more formally as follows.

Clock Condition. For any events a,ba, b:

if a→b then C(a)<C(b).\text{if } a \rightarrow b \text{ then } C(a) < C(b).

Note that we cannot expect the converse condition to hold as well, since that would imply that any two concurrent events must occur at the same time. In Figure 1, p2p_2 and p3p_3 are both concurrent with q3q_3, so this would mean that they both must occur at the same time as q3q_3, which would contradict the Clock Condition because p2→p3p_2 \rightarrow p_3.

It is easy to see from our definition of the relation "→\rightarrow" that the Clock Condition is satisfied if the following two conditions hold.

C1. If aa and bb are events in process PiP_i, and aa comes before bb, then Ci(a)<Ci(b)C_i(a) < C_i(b).

C2. If aa is the sending of a message by process PiP_i and bb is the receipt of that message by process PjP_j, then Ci(a)<Cj(b)C_i(a) < C_j(b).

Let us consider the clocks in terms of a space-time diagram. We imagine that a process' clock "ticks" through every number, with the ticks occurring between the process' events. For example, if aa and bb are consecutive events in process PiP_i with Ci(a)=4C_i(a) = 4 and Ci(b)=7C_i(b) = 7, then clock ticks 5, 6, and 7 occur between the two events. We draw a dashed "tick line" through all the like-numbered ticks of the different processes. The space-time diagram of Figure 1 might then yield the picture in Figure 2. Condition C1 means that there must be a tick line between any two events on a process line, and condition C2 means that every message line must cross a tick line. From the pictorial meaning of →\rightarrow, it is easy to see why these two conditions imply the Clock Condition.

We can consider the tick lines to be the time coordinate lines of some Cartesian coordinate system on space-time. We can redraw Figure 2 to straighten these coordinate lines, thus obtaining Figure 3. Figure 3 is a valid alternate way of representing the same system of events as Figure 2. Without introducing the concept of physical time into the system (which requires introducing physical clocks), there is no way to decide which of these pictures is a better representation.

The reader may find it helpful to visualize a two-dimensional spatial network of processes, which yields a three-dimensional space-time diagram. Processes and messages are still represented by lines, but tick lines become two-dimensional surfaces.

Let us now assume that the processes are algorithms, and the events represent certain actions during their execution. We will show how to introduce clocks into the processes which satisfy the Clock Condition. Process PiP_i's clock is represented by a register CiC_i, so that Ci(a)C_i(a) is the value contained by CiC_i during the event aa. The value of CiC_i will change between events, so changing CiC_i does not itself constitute an event.

To guarantee that the system of clocks satisfies the Clock Condition, we will insure that it satisfies conditions C1 and C2. Condition C1 is simple; the processes need only obey the following implementation rule:

IR1. Each process PiP_i increments CiC_i between any two successive events.

To meet condition C2, we require that each message mm contain a timestamp TmT_m which equals the time at which the message was sent. Upon receiving a message timestamped TmT_m, a process must advance its clock to be later than TmT_m. More precisely, we have the following rule.

IR2. (a) If event aa is the sending of a message mm by process PiP_i, then the message mm contains a timestamp Tm=Ci(a)T_m = C_i(a). (b) Upon receiving a message mm, process PjP_j sets CjC_j greater than or equal to its present value and greater than TmT_m.

In IR2(b) we consider the event which represents the receipt of the message mm to occur after the setting of CjC_j. (This is just a notational nuisance, and is irrelevant in any actual implementation.) Obviously, IR2 insures that C2 is satisfied. Hence, the simple implementation rules IR1 and IR2 imply that the Clock Condition is satisfied, so they guarantee a correct system of logical clocks.

Ordering the Events Totally

We can use a system of clocks satisfying the Clock Condition to place a total ordering on the set of all system events. We simply order the events by the times at which they occur. To break ties, we use any arbitrary total ordering << of the processes. More precisely, we define a relation ⇒\Rightarrow as follows: if aa is an event in process PiP_i and bb is an event in process PjP_j, then a⇒ba \Rightarrow b if and only if either (i) Ci(a)<Cj(b)C_i(a) < C_j(b) or (ii) Ci(a)=Cj(b)C_i(a) = C_j(b) and Pi<PjP_i < P_j. It is easy to see that this defines a total ordering, and that the Clock Condition implies that if a→ba \rightarrow b then a⇒ba \Rightarrow b. In other words, the relation ⇒\Rightarrow is a way of completing the “happened before” partial ordering to a total ordering.3^3

The ordering ⇒\Rightarrow depends upon the system of clocks CiC_i, and is not unique. Different choices of clocks which satisfy the Clock Condition yield different relations ⇒\Rightarrow. Given any total ordering relation ⇒\Rightarrow which extends →\rightarrow, there is a system of clocks satisfying the Clock Condition which yields that relation. It is only the partial ordering →\rightarrow which is uniquely determined by the system of events.

Being able to totally order the events can be very useful in implementing a distributed system. In fact, the reason for implementing a correct system of logical clocks is to obtain such a total ordering. We will illustrate the use of this total ordering of events by solving the following version of the mutual exclusion problem. Consider a system composed of a fixed collection of processes which share a single resource. Only one process can use the resource at a time, so the processes must synchronize themselves to avoid conflict. We wish to find an algorithm for granting the resource to a process which satisfies the following three conditions: (I) A process which has been granted the resource must release it before it can be granted to another process. (II) Different requests for the resource must be granted in the order in which they are made. (III) If every process which is granted the resource eventually releases it, then every request is eventually granted.

We assume that the resource is initially granted to exactly one process.

These are perfectly natural requirements. They precisely specify what it means for a solution to be correct.4^4 Observe how the conditions involve the ordering of events. Condition II says nothing about which of two concurrently issued requests should be granted first.

It is important to realize that this is a nontrivial problem. Using a central scheduling process which grants requests in the order they are received will not work, unless additional assumptions are made. To see this, let P0P_0 be the scheduling process. Suppose P1P_1 sends a request to P0P_0 and then sends a message to P2P_2. Upon receiving the latter message, P2P_2 sends a request to P0P_0. It is possible for P2P_2's request to reach P0P_0 before P1P_1's request does. Condition II is then violated if P2P_2's request is granted first.

To solve the problem, we implement a system of clocks with rules IR1 and IR2, and use them to define a total ordering ⇒\Rightarrow of all events. This provides a total ordering of all request and release operations. With this ordering, finding a solution becomes a straightforward exercise. It just involves making sure that each process learns about all other processes’ operations.

To simplify the problem, we make some assumptions. They are not essential, but they are introduced to avoid distracting implementation details. We assume first of all that for any two processes PiP_i and PjP_j, the messages sent from PiP_i to PjP_j are received in the same order as they are sent. Moreover, we assume that every message is eventually received. (These assumptions can be avoided by introducing message numbers and message acknowledgment protocols.) We also assume that a process can send messages directly to every other process.

Each process maintains its own request queue which is never seen by any other process. We assume that the request queues initially contain the single message T0:P0T_0 : P_0 requests resource, where P0P_0 is the process initially granted the resource and T0T_0 is less than the initial value of any clock.

The algorithm is then defined by the following five rules. For convenience, the actions defined by each rule are assumed to form a single event.

  1. To request the resource, process PiP_i sends the message Tm:PiT_m : P_i requests resource to every other process, and puts that message on its request queue, where TmT_m is the timestamp of the message.
  2. When process PjP_j receives the message Tm:PiT_m : P_i requests resource, it places it on its request queue and sends a (timestamped) acknowledgment message to PiP_i.5^5
  3. To release the resource, process PiP_i removes any Tm:PiT_m : P_i requests resource message from its request queue and sends a (timestamped) PiP_i releases resource message to every other process.
  4. When process PjP_j receives a PiP_i releases resource message, it removes any Tm:PiT_m : P_i requests resource message from its request queue.
  5. Process PiP_i is granted the resource when the following two conditions are satisfied: (i) There is a Tm:PiT_m : P_i requests resource message in its request queue which is ordered before any other request in its queue by the relation ⇒\Rightarrow. (To define the relation “⇒\Rightarrow” for messages, we identify a message with the event of sending it.) (ii) PiP_i has received a message from every other process timestamped later than TmT_m.6^6

Note that conditions (i) and (ii) of rule 5 are tested locally by PiP_i.

It is easy to verify that the algorithm defined by these rules satisfies conditions I–III. First of all, observe that condition (ii) of rule 5, together with the assumption that messages are received in order, guarantees that PiP_i has learned about all requests which preceded its current

\footnotetext{ 3^3 The ordering << establishes a priority among the processes. If a “fairer” method is desired, then << can be made a function of the clock value. For example, if Ci(a)=Cj(b)C_i(a) = C_j(b) and j<ij < i, then we can let a⇒ba \Rightarrow b if j<Ci(a)mod  N≤ij < C_i(a) \mod N \leq i, and b⇒ab \Rightarrow a otherwise; where NN is the total number of processes. 4^4 The term “eventually” should be made precise, but that would require too long a diversion from our main topic. 5^5 This acknowledgment message need not be sent if PjP_j has already sent a message to PiP_i timestamped later than TmT_m. 6^6 If Pi<PjP_i < P_j, then PiP_i need only have received a message timestamped ≥Tm\geq T_m from PjP_j. }

Communications July 1978 of Volume 21 the ACM Number 7 request. Since rules 3 and 4 are the only ones which delete messages from the request queue, it is then easy to see that condition I holds. Condition II follows from the fact that the total ordering ⇒\Rightarrow extends the partial ordering →\rightarrow. Rule 2 guarantees that after P_i requests the resource, condition (ii) of rule 5 will eventually hold. Rules 3 and 4 imply that if each process which is granted the resource eventually releases it, then condition (i) of rule 5 will eventually hold, thus proving condition III.

This is a distributed algorithm. Each process independently follows these rules, and there is no central synchronizing process or central storage. This approach can be generalized to implement any desired synchronization for such a distributed multiprocess system. The synchronization is specified in terms of a State Machine, consisting of a set CC of possible commands, a set SS of possible states, and a function e:C×S→Se : C \times S \to S. The relation e(C,S)=S′e(C, S) = S' means that executing the command CC with the machine in state SS causes the machine state to change to S′S'. In our example, the set CC consists of all the commands PiP_i requests resource and PiP_i releases resource, and the state consists of a queue of waiting request commands, where the request at the head of the queue is the currently granted one. Executing a request command adds the request to the tail of the queue, and executing a release command removes a command from the queue.\footnote{If each process does not strictly alternate request and release commands, then executing a release command could delete zero, one, or more than one request from the queue.}

Each process independently simulates the execution of the State Machine, using the commands issued by all the processes. Synchronization is achieved because all processes order the commands according to their timestamps (using the relation ⇒\Rightarrow), so each process uses the same sequence of commands. A process can execute a command timestamped T when it has learned of all commands issued by all other processes with timestamps less than or equal to T. The precise algorithm is straightforward, and we will not bother to describe it.

This method allows one to implement any desired form of multiprocess synchronization in a distributed system. However, the resulting algorithm requires the active participation of all the processes. A process must know all the commands issued by other processes, so that the failure of a single process will make it impossible for any other process to execute State Machine commands, thereby halting the system.

The problem of failure is a difficult one, and it is beyond the scope of this paper to discuss it in any detail. We will just observe that the entire concept of failure is only meaningful in the context of physical time. Without physical time, there is no way to distinguish a failed process from one which is just pausing between events. A user can tell that a system has “crashed” only because he has been waiting too long for a response. A method which works despite the failure of individual processes or communication lines is described in [3].

Anomalous Behavior

Our resource scheduling algorithm ordered the requests according to the total ordering ⇒\Rightarrow. This permits the following type of “anomalous behavior.” Consider a nationwide system of interconnected computers. Suppose a person issues a request A on a computer A, and then telephones a friend in another city to have him issue a request B on a different computer B. It is quite possible for request B to receive a lower timestamp and be ordered before request A. This can happen because the system has no way of knowing that A actually preceded B, since that precedence information is based on messages external to the system.

Let us examine the source of the problem more closely. Let S\mathcal{S} be the set of all system events. Let us introduce a set of events which contains the events in S\mathcal{S} together with all other relevant external events, such as the phone calls in our example. Let →\rightarrow denote the “happened before” relation for S\mathcal{S}. In our example, we had A →\rightarrow B, but A ↛\not\rightarrow B. It is obvious that no algorithm based entirely upon events in S\mathcal{S}, and which does not relate those events in any way with the other events in L\mathcal{L}, can guarantee that request A is ordered before request B.

There are two possible ways to avoid such anomalous behavior. The first way is to explicitly introduce into the system the necessary information about the ordering →\rightarrow. In our example, the person issuing request A could receive the timestamp T_A of that request from the system. When issuing request B, his friend could specify that B be given a timestamp later than T_A. This gives the user the responsibility for avoiding anomalous behavior.

The second approach is to construct a system of clocks which satisfies the following condition.

Strong Clock Condition. For any events a,ba, b in S\mathcal{S}:

if a→b then C(a)<C(b).\text{if } a \rightarrow b \text{ then } C(a) < C(b).

This is stronger than the ordinary Clock Condition because →\rightarrow is a stronger relation than →\rightarrow. It is not in general satisfied by our logical clocks.

Let us identify S\mathcal{S} with some set of “real” events in physical space-time, and let →\rightarrow be the partial ordering of events defined by special relativity. One of the mysteries of the universe is that it is possible to construct a system of physical clocks which, running quite independently of one another, will satisfy the Strong Clock Condition. We can therefore use physical clocks to eliminate anomalous behavior. We now turn our attention to such clocks.

Physical Clocks

Let us introduce a physical time coordinate into our space-time picture, and let Ci(t)C_i(t) denote the reading of the clock CiC_i at physical time tt.\footnote{We will assume a Newtonian space-time. If the relative motion of the clocks or gravitational effects are not negligible, then Ci(t)C_i(t) must be deduced from the actual clock reading by transforming from proper time to the arbitrarily chosen time coordinate.} For mathematical convenience, we assume that the clocks run continuously rather than in discrete “ticks.” (A discrete clock can be thought of as a continuous one in which there is an error of up to 12\frac{1}{2} “tick” in reading it.) More precisely, we assume that Ci(t)C_i(t) is a continuous, differentiable function of tt except for isolated jump discontinuities where the clock is reset. Then dCi(t)/dtdC_i(t)/dt represents the rate at which the clock is running at time tt.

In order for the clock CiC_i to be a true physical clock, it must run at approximately the correct rate. That is, we must have dCi(t)/dt≈1dC_i(t)/dt \approx 1 for all tt. More precisely, we will assume that the following condition is satisfied:

PC1. There exists a constant κ≪1\kappa \ll 1 such that for all ii: ∣dCi(t)/dt−1∣<κ|dC_i(t)/dt - 1| < \kappa. For typical crystal controlled clocks, κ≤10−6\kappa \leq 10^{-6}.

It is not enough for the clocks individually to run at approximately the correct rate. They must be synchronized so that Ci(t)≈Cj(t)C_i(t) \approx C_j(t) for all i,ji, j, and tt. More precisely, there must be a sufficiently small constant ϵ\epsilon so that the following condition holds:

PC2. For all i,ji, j: ∣Ci(t)−Cj(t)∣<ϵ|C_i(t) - C_j(t)| < \epsilon.

If we consider vertical distance in Figure 2 to represent physical time, then PC2 states that the variation in height of a single tick line is less than ϵ\epsilon.

Since two different clocks will never run at exactly the same rate, they will tend to drift further and further apart. We must therefore devise an algorithm to insure that PC2 always holds. First, however, let us examine how small κ\kappa and ϵ\epsilon must be to prevent anomalous behavior. We must insure that the system L\mathcal{L} of relevant physical events satisfies the Strong Clock Condition. We assume that our clocks satisfy the ordinary Clock Condition, so we need only require that the Strong Clock Condition holds when aa and bb are events in L\mathcal{L} with a↮ba \not\leftrightarrow b. Hence, we need only consider events occurring in different processes.

Let μ\mu be a number such that if event aa occurs at physical time tt and event bb in another process satisfies a→ba \rightarrow b, then bb occurs later than physical time t+μt + \mu. In other words, μ\mu is less than the shortest transmission time for interprocess messages. We can always choose μ\mu equal to the shortest distance between processes divided by the speed of light. However, depending upon how messages in L\mathcal{L} are transmitted, μ\mu could be significantly larger.

To avoid anomalous behavior, we must make sure that for any i,ji, j, and tt: Ci(t+μ)−Cj(t)>0C_i(t + \mu) - C_j(t) > 0. Combining this with PC1 and 2 allows us to relate the required smallness of κ\kappa and ϵ\epsilon to the value of μ\mu as follows. We assume that when a clock is reset, it is always set forward and never back. (Setting it back could cause Cl to be violated.) PC1 then implies that Ci(t+μ)−Ci(t)>(1−κ)μC_i(t + \mu) - C_i(t) > (1 - \kappa)\mu. Using PC2, it is then easy to deduce that Ci(t+μ)−Cj(t)>0C_i(t + \mu) - C_j(t) > 0 if the following inequality holds:

ϵ/(1−κ)≤μ\epsilon/(1 - \kappa) \leq \mu.

This inequality together with PC1 and PC2 implies that anomalous behavior is impossible.

We now describe our algorithm for insuring that PC2 holds. Let mm be a message which is sent at physical time tt and received at time t′t'. We define vm=t′−tv_m = t' - t to be the total delay of the message mm. This delay will, of course, not be known to the process which receives mm. However, we assume that the receiving process knows some minimum delay μm≥0\mu_m \geq 0 such that μm≤vm\mu_m \leq v_m. We call ξm=vm−μm\xi_m = v_m - \mu_m the unpredictable delay of the message.

We now specialize rules IR1 and 2 for our physical clocks as follows:

IR1'. For each ii, if PiP_i does not receive a message at physical time tt, then CiC_i is differentiable at tt and dCi(t)/dt>0dC_i(t)/dt > 0.

IR2'. (a) If PiP_i sends a message mm at physical time tt, then mm contains a timestamp Tm=Ci(t)T_m = C_i(t). (b) Upon receiving a message mm at time t′t', process PjP_j sets Cj(t′)C_j(t') equal to maximum (Cj(t′−0),Tm+μm)(C_j(t' - 0), T_m + \mu_m).\footnote{C_j(t' - 0) = \lim_{\delta \to 0} C_j(t' - |\delta|).}

Although the rules are formally specified in terms of the physical time parameter, a process only needs to know its own clock reading and the timestamps of messages it receives. For mathematical convenience, we are assuming that each event occurs at a precise instant of physical time, and different events in the same process occur at different times. These rules are then specializations of rules IR1 and IR2, so our system of clocks satisfies the Clock Condition. The fact that real events have a finite duration causes no difficulty in implementing the algorithm. The only real concern in the implementation is making sure that the discrete clock ticks are frequent enough so Cl is maintained.

We now show that this clock synchronizing algorithm can be used to satisfy condition PC2. We assume that the system of processes is described by a directed graph in which an arc from process PiP_i to process PjP_j represents a communication line over which messages are sent directly from PiP_i to PjP_j. We say that a message is sent over this arc every τ\tau seconds if for any tt, PiP_i sends at least one message to PjP_j between physical times tt and t+τt + \tau. The diameter of the directed graph is the smallest number dd such that for any pair of distinct processes Pj,PkP_j, P_k, there is a path from PjP_j to PkP_k having at most dd arcs.

In addition to establishing PC2, the following theorem bounds the length of time it can take the clocks to become synchronized when the system is first started.

Theorem. Assume a strongly connected graph of processes with diameter dd which always obeys rules IR1' and IR2'. Assume that for any message mm, μm≤μ\mu_m \leq \mu for some constant μ\mu, and that for all t≥t0t \geq t_0: (a) PC1 holds. (b) There are constants τ\tau and ξ\xi such that every τ\tau seconds a message with an unpredictable delay less than ξ\xi is sent over every arc. Then PC2 is satisfied with ϵ≈d(2κτ+ξ)\epsilon \approx d(2\kappa\tau + \xi) for all t≥t0+τdt \geq t_0 + \tau d, where the approximations assume μ+ξ≪τ\mu + \xi \ll \tau.

The proof of this theorem is surprisingly difficult, and is given in the Appendix. There has been a great deal of work done on the problem of synchronizing physical clocks. We refer the reader to [4] for an introduction to the subject. The methods described in the literature are useful for estimating the message delays μm\mu_m and for adjusting the clock frequencies dCi/dtdC_i/dt for clocks which permit such an adjustment. However, the requirement that clocks are never set backward seems to distinguish our situation from ones previously studied, and we believe this theorem to be a new result.

Conclusion

We have seen that the concept of “happening before” defines an invariant partial ordering of the events in a distributed multiprocess system. We described an algorithm for extending that partial ordering to a somewhat arbitrary total ordering, and showed how this total ordering can be used to solve a simple synchronization problem. A future paper will show how this approach can be extended to solve any synchronization problem.

The total ordering defined by the algorithm is somewhat arbitrary. It can produce anomalous behavior if it disagrees with the ordering perceived by the system’s users. This can be prevented by the use of properly synchronized physical clocks. Our theorem showed how closely the clocks can be synchronized.

In a distributed system, it is important to realize that the order in which events occur is only a partial ordering. We believe that this idea is useful in understanding any multiprocess system. It should help one to understand the basic problems of multiprocessing independently of the mechanisms used to solve them.

Proof of the Theorem

Appendix

For any ii and tt, let us define CitC_i^t to be a clock which is set equal to CiC_i at time tt and runs at the same rate as CiC_i, but is never reset. In other words,

Cit(t′)=Ci(t)+∫tt′[dCi(t)/dt]dt(1)C_i^t(t')=C_i(t)+\int_t^{t'}[dC_i(t)/dt]dt \tag{1}
(1)

for all t′≥tt' \ge t. Note that

Ci(t′)≥Cit(t′)C_i(t') \ge C_i^t(t')

for all t′≥tt' \ge t.

Suppose process P1P_1 at time t1t_1 sends a message to process P2P_2 which is received at time t2t_2 with an unpredictable delay ≤ξ\le \xi, where t0≤t1≤t2t_0 \le t_1 \le t_2. Then for all t≥t2t \ge t_2 we have:

C2t(t)≥C2t(t2)+(1−κ)(t−t2)C_2^t(t) \ge C_2^t(t_2)+(1-\kappa)(t-t_2)

[by (1) and PC1]

≥C1(t1)+μm+(1−κ)(t−t2)\ge C_1(t_1)+\mu_m+(1-\kappa)(t-t_2)

[by IR2′(b)]

=C1(t1)+(1−κ)(t−t1)−[(t2−t1)−μm]+κ(t2−t1)=C_1(t_1)+(1-\kappa)(t-t_1)-[(t_2-t_1)-\mu_m]+ \kappa(t_2-t_1)
≥C1(t1)+(1−κ)(t−t1)−ξ.\ge C_1(t_1)+(1-\kappa)(t-t_1)-\xi.

Hence, with these assumptions, for all t≥t2t\ge t_2 we have:

C2t(t)≥C1(t1)+(1−κ)(t−t1)−ξ.(3)C_2^t(t)\ge C_1(t_1)+(1-\kappa)(t-t_1)-\xi. \tag{3}
(3)

Now suppose that for i=1,…,ni=1,\ldots,n we have ti≤ti′<ti+1t_i\le t_i'<t_{i+1}, ti+1,t0≤t1t_{i+1},t_0\le t_1, and that at time tit_i process PiP_i sends a message to process Pi+1P_{i+1} which is received at time ti+1t_{i+1} with an unpredictable delay less than ξ\xi. Then repeated application of the inequality (3) yields the following result for t≥tn+1t\ge t_{n+1}:

Cn+1t(t)≥C1(t1)+(1−κ)(t−t1)−nξ.(4)C_{n+1}^t(t)\ge C_1(t_1)+(1-\kappa)(t-t_1)-n\xi. \tag{4}
(4)

From PC1, IR1′ and 2′ we deduce that

C1(t1′)≥C1(t1)+(1−κ)(t1′−t1).C_1(t_1')\ge C_1(t_1)+(1-\kappa)(t_1'-t_1).

Combining this with (4) and using (2), we get

Cn+1(t)≥C1(t1)+(1−κ)(t−t1)−nξ(5)C_{n+1}(t)\ge C_1(t_1)+(1-\kappa)(t-t_1)-n\xi \tag{5}
(5)

for t≥tn+1t\ge t_{n+1}.

For any two processes PP and P′P', we can find a sequence of processes P=P0,P1,…,Pn+1=P′,n≤dP=P_0,P_1,\ldots,P_{n+1}=P', n\le d, with communication arcs from each PiP_i to Pi+1P_{i+1}. By hypothesis (b) we can find times ti,ti′t_i,t_i' with ti′−ti≤τt_i'-t_i\le\tau and ti+1−ti′≤νt_{i+1}-t_i'\le\nu, where ν=μ+ξ\nu=\mu+\xi. Hence, an inequality of the form (5) holds with n≤dn\le d whenever t≥t1+d(τ+ν)t\ge t_1+d(\tau+\nu). For any i,ji,j and any t,t1t,t_1 with t1≥t0t_1\ge t_0 and t≥t1+d(τ+ν)t\ge t_1+d(\tau+\nu) we therefore have:

Ci(t)≥Cj(t1)+(1−κ)(t−t1)−dξ.(6)C_i(t)\ge C_j(t_1)+(1-\kappa)(t-t_1)-d\xi. \tag{6}
(6)

Now let mm be any message timestamped TmT_m, and suppose it is sent at time tt and received at time t′t'. We pretend that mm has a clock CmC_m which runs at a constant rate such that Cm(t)=tmC_m(t)=t_m and Cm(t′)=tm+μmC_m(t')=t_m+\mu_m. Then ∣t′−t∣≤μ|t'-t|\le\mu implies that dCm/dt≤1dC_m/dt\le1. Rule IR2′(b) simply sets Cj(t′)C_j(t') to maximum (Cj(t′−0),Cm(t′))(C_j(t'-0),C_m(t')). Hence, clocks are reset only by setting them equal to other clocks.

For any time tx≥t0+μ/(1−κ)t_x\ge t_0+\mu/(1-\kappa), let CxC_x be the clock having the largest value at time txt_x. Since all clocks run at a rate less than 1+κ1+\kappa, we have for all ii and all t≥txt\ge t_x:

Ci(t)≤Cx(tx)+(1+κ)(t−tx).(7)C_i(t)\le C_x(t_x)+(1+\kappa)(t-t_x). \tag{7}
(7)

We now consider the following two cases: (i) CxC_x is the clock CqC_q of process PqP_q. (ii) CxC_x is the clock CmC_m of a message sent at time t1t_1 by process PqP_q. In case (i), (7) simply becomes

Ci(t)≤Cq(tx)+(1+κ)(t−tx).(8i)C_i(t)\le C_q(t_x)+(1+\kappa)(t-t_x). \tag{8i}
(8i)

In case (ii), since Cm(t1)=Cq(t1)C_m(t_1)=C_q(t_1) and dCm/dt≤1dC_m/dt\le1, we have

Cx(tx)≤Cq(t1)+(tx−t1).C_x(t_x)\le C_q(t_1)+(t_x-t_1).

Hence, (7) yields

Ci(t)≤Cq(t1)+(1+κ)(t−t1).(8ii)C_i(t)\le C_q(t_1)+(1+\kappa)(t-t_1). \tag{8ii}
(8ii)

Since tx≥t0+μ/(1−κ)t_x\ge t_0+\mu/(1-\kappa), we get

Cq(tx−μ/(1−κ))≤Cq(tx)−μC_q(t_x-\mu/(1-\kappa))\le C_q(t_x)-\mu

[by PC1]

≤Cm(tx)−μ\le C_m(t_x)-\mu

[by choice of mm]

≤Cm(tx)−(tx−t1)μm/νm\le C_m(t_x)-(t_x-t_1)\mu_m/\nu_m

[by μm≤μ\mu_m\le\mu and tx−t1≤νmt_x-t_1\le\nu_m]

=Tm=T_m

[by definition of CmC_m]

=Cq(t1)=C_q(t_1)

[by IR2′(a)].

Hence, Cq(tx−μ/(1−κ))≤Cq(t1)C_q(t_x-\mu/(1-\kappa))\le C_q(t_1), so tx−t1≤μ/(1−κ)t_x-t_1\le\mu/(1-\kappa) and thus t1≥t0t_1\ge t_0.

Letting t1=txt_1 = t_x in case (i), we can combine (8i) and (8ii) to deduce that for any t,txt, t_x with t≥tx≥t0+μ/(1−κ)t \geq t_x \geq t_0 + \mu/(1 - \kappa) there is a process PqP_q and a time t1t_1 with tx−μ/(1−κ)≤t1≤txt_x - \mu/(1 - \kappa) \leq t_1 \leq t_x such that for all ii:

Ci(t)≤Cq(t1)+(1+κ)(t−t1).C_i(t) \leq C_q(t_1) + (1 + \kappa)(t - t_1).

Choosing tt and txt_x with t≥tx+d(τ+ν)t \geq t_x + d(\tau + \nu), we can combine (6) and (9) to conclude that there exists a t1t_1 and a process PqP_q such that for all ii:

Cq(t1)+(1−κ)(t−t1)−dξ≤Ci(t)C_q(t_1) + (1 - \kappa)(t - t_1) - d\xi \leq C_i(t)
≤Cq(t1)+(1+κ)(t−t1)\leq C_q(t_1) + (1 + \kappa)(t - t_1)

Letting t=tx+d(τ+ν)t = t_x + d(\tau + \nu), we get

d(τ+ν)≤t−t1≤d(τ+ν)+μ/(1−κ).d(\tau + \nu) \leq t - t_1 \leq d(\tau + \nu) + \mu/(1 - \kappa).

Combining this with (10), we get

Cq(t1)+(t−t1)−κd(τ+ν)−dξ≤Ci(t)≤Cq(t1)C_q(t_1) + (t - t_1) - \kappa d(\tau + \nu) - d\xi \leq C_i(t) \leq C_q(t_1)
+(t−t1)+κ[d(τ+ν)+μ/(1−κ)]+ (t - t_1) + \kappa[d(\tau + \nu) + \mu/(1 - \kappa)]

Using the hypotheses that κ≪1\kappa \ll 1 and μ≤ν≪τ\mu \leq \nu \ll \tau, we can rewrite (11) as the following approximate inequality.

Cq(t1)+(t−t1)−d(κτ+ξ)≤Ci(t)C_q(t_1) + (t - t_1) - d(\kappa \tau + \xi) \leq C_i(t)
≤Cq(t1)+(t−t1)+dκτ.\leq C_q(t_1) + (t - t_1) + d\kappa \tau.

Since this holds for all ii, we get

∣Ci(t)−Cj(t)∣≤d(2κτ+ξ),|C_i(t) - C_j(t)| \leq d(2\kappa \tau + \xi),

and this holds for all t≥t0+dτt \geq t_0 + d\tau.

Note that relation (11) of the proof yields an exact upper bound for ∣Ci(t)−Cj(t)∣|C_i(t) - C_j(t)| in case the assumption μ+ξ≪τ\mu + \xi \ll \tau is invalid. An examination of the proof suggests a simple method for rapidly initializing the clocks, or resynchronizing them if they should go out of synchrony for any reason. Each process sends a message which is relayed to every other process. The procedure can be initiated by any process, and requires less than 2d(μ+ξ)2d(\mu + \xi) seconds to effect the synchronization, assuming each of the messages has an unpredictable delay less than ξ\xi.

Acknowledgment. The use of timestamps to order operations, and the concept of anomalous behavior are due to Paul Johnson and Robert Thomas.

Received March 1976; revised October 1977

References

  1. Schwartz, J.T. Relativity in Illustrations. New York U. Press, New York, 1962.
  2. Taylor, E.F., and Wheeler, J.A. Space-Time Physics, W.H. Freeman, San Francisco, 1966.
  3. Lamport, L. The implementation of reliable distributed multiprocess systems. To appear in Computer Networks.
  4. Ellingson, C., and Kulpinski, R.J. Dissemination of system-time. IEEE Trans. Comm. Com-23, 5 (May 1973), 605–624. Programming Languages J. J. Horning Editor Shallow Binding in Lisp 1.5 Henry G. Baker, Jr. Massachusetts Institute of Technology Shallow binding is a scheme which allows the value of a variable to be accessed in a bounded amount of computation. An elegant model for shallow binding in Lisp 1.5 is presented in which context-switching is an environment tree transformation called rerooting. Rerooting is completely general and reversible, and is optional in the sense that a Lisp 1.5 interpreter will operate correctly whether or not rerooting is invoked on every context change. Since rerooting leaves assoc [v, a] invariant, for all variables v and all environments a, the programmer can have access to a rerooting primitive, shallow[], which gives him dynamic control over whether accesses are shallow or deep, and which affects only the speed of execution of a program, not its semantics. In addition, multiple processes can be active in the same environment structure, so long as rerooting is an indivisible operation. Finally, the concept of rerooting is shown to combine the concept of shallow binding in Lisp with Dijkstra’s display for Algol and hence is a general model for shallow binding. Key Words and Phrases: Lisp 1.5, environment trees, FUNARG’s, shallow binding, deep binding, multiprogramming, Algol display CR Categories: 4.13, 4.22, 4.32 General permission to make fair use in teaching or research of all or part of this material is granted to individual readers and to nonprofit libraries acting for them provided that ACM’s copyright notice is given and that reference is made to the publication, to its date of issue, and to the fact that reprinting privileges were granted by permission of the Association for Computing Machinery. To otherwise reprint a figure, table, other substantial excerpt, or the entire work requires specific permission as does republication, or systematic or multiple reproduction. This research was supported by the Advanced Research Projects Agency of the Department of Defense and was monitored by the Office of Naval Research under contract number N00014-75-C-0522. Author’s present address: Computer Science Department, University of Rochester, Rochester, NY 14627. © 1978 ACM 0001-0782/78/0700-0565 \$00.75 Communications of the ACM July 1978 Volume 21 Number 7

Read off the page by a vision model reading the page images using gpt-5.