Solving Tasks with Fewer Registers Than Processes
Abstract
This paper studies distributed-computing tasks through the lens of space complexity in the read/write wait-free model, defined as the number of multi-reader-multi-writer atomic read/write registers needed to solve a task using a wait-free algorithm. Surprisingly, even though the read/write wait-free model is at the foundation of distributed computing, previous work on space complexity has focused on synchronization primitives stronger than read/write registers or on weaker progress conditions.
The paper reveals that the read/write wait-free model offers a rich space-complexity landscape: (1) assuming non-anonymous processes, it shows that there is an infinite hierarchy of tasks of increasing space complexity; (2) it shows that space complexity separates anonymous from non-anonymous memory; (3) regardless of process or register anonymity, it exhibits a task of space complexity two, which is the minimal non-trivial space complexity; (4) finally, it shows that subcases of the adopt-commit task have different space complexity in non-anonymous memory under bounded wait-freedom.
Keywords and phrases:
Asynchrony, Read/write registers, Wait-freedom, Tasks, Covering argument, Lower bound, Space complexity, Anonymous Processes, Anonymous MemoryCopyright and License:
2012 ACM Subject Classification:
Theory of computation Distributed algorithmsEditors:
Andrei Arusoaie, Emanuel Onica, Michael Spear, and Sara Tucci-PiergiovanniSeries and Publisher:
Leibniz International Proceedings in Informatics, Schloss Dagstuhl – Leibniz-Zentrum für Informatik
1 Introduction
Parallel Computing is the science of breaking down data-processing problems into independent parts that can be performed simultaneously by multiple processors to maximize performance. The nature of Distributed Computing is different: it is the science of (formalized) cooperation among independent computing entities [34]. At its core, it consists of designing and classifying distributed abstractions, each of which captures a specific form of cooperation. For example, Herlihy’s famous wait-free hierarchy [23] classifies distributed abstractions called objects according to the maximum number of wait-free processes that can solve consensus when they have access to instances of the object and read/write registers.
There are a large number of distributed abstractions and computing models in which to study them. However, one of the simplest possible settings is to consider distributed abstractions called tasks in the read/write wait-free model. Tasks are cooperation abstractions in which a number of processes each receive a single input and must produce a single output. The task’s specification relates assignments of inputs to processes to allowed assignments of outputs to processes. To solve a task in the read/write wait-free model, processes must communicate through atomic read/write registers only, and each process that takes sufficiently many steps must eventually output, regardless of what other processes do.
Surprisingly, there is no systematic classification of tasks in this simple setting. Here, Herlihy’s hierarchy is not informative, since consensus is not wait-free solvable with only read/write registers, and therefore such tasks are at level 1 of the consensus hierarchy.
This paper studies the classification of read/write wait-free solvable tasks according to the minimum number of atomic read/write registers needed (without a limit on register size) to solve the task wait-free. We call this number the read/write space complexity of a task (abbreviated space complexity in the rest of the paper). The space complexity of a task may vary depending on whether processes and registers are anonymous or not, and we consider all four possible anonymity combinations. Many previous works study other notions of space complexity (see Section 7), often based on primitives stronger than read/write registers or under progress conditions weaker than wait-freedom, but little is known about the space complexity of tasks in the read/write wait-free model.
Delporte-Gallet et al. [12] show that, for non-anonymous wait-free processes in non-anonymous memory, registers (where is the number of processes) are sufficient to solve any read/write wait-free solvable task even if registers are not pre-allocated to processes111Nevertheless, they make the wrong claim that registers are also necessary to implement any wait-free solvable task. Thus, at least in the non-anonymous case, space complexity is only interesting when there are fewer registers than processes. Some tasks are known to be implementable wait-free with fewer registers than processes. For example, the splitter [29] and the binary conflict-detector task [4] are solvable wait-free with just non-anonymous registers; other tasks, such as lattice agreement [5], require registers [12]. However, beyond these few examples, the space complexity of read/write wait-free solvable tasks has so far not been systematically explored.
The paper shows that the read/write wait-free model offers a rich space-complexity landscape by presenting novel space-complexity separation results:
Section 3 shows that for non-anonymous processes, whether registers are anonymous or not, there is a task of space complexity for every integer . Thus, assuming non-anonymous processes, every level of the space complexity hierarchy is populated. The lower bound needed for this result is obtained using a classic covering argument in the spirit of Burns and Lynch [7].
Section 4 shows that space complexity separates non-anonymous registers from anonymous registers by showing that, regardless of process anonymity, binary adopt-commit has space complexity 3 if the registers are non-anonymous and space complexity if the registers are anonymous. This is an interesting result because recent work [26] conjectures that read/write wait-free solvability of tasks, when the number of registers is not constrained, does not depend on register anonymity.
Section 5 presents the contention-detection task, and it shows that it achieves the weakest non-trivial space complexity – i.e., two – regardless of process or register anonymity.
Section 6 shows that space complexity separates sub-cases of the adopt-commit task: assuming each process receives as input one of two values drawn from a set of three values, adopt-commit is solvable bounded wait-free with three non-anonymous registers, but if the two values are drawn from a set of four values, then four registers are needed. Finally, Section 7 surveys related work and Section 8 concludes with open questions.
2 Computation Model
The computing model is the standard asynchronous wait-free model for deterministic, unbounded-state processes communicating using shared atomic, multi-reader-multi-writer (MRMW) read/write registers of unbounded size. The set of processes may be countably infinite or limited to processes.
A run in the model is a (possibly infinite) sequence of atomic steps. Each step is taken by a single process, which applies either a read or a write operation to a shared register and then updates its private state. A read operation returns the current value of the register, and a write operation takes a value parameter and replaces the current contents of the register with the provided value. Processes run an algorithm, and the operation applied by a process in a step is determined by the algorithm as a function of the local state of the process before the step. Since we focus exclusively on solving tasks, we assume that, in each run, each process initially receives a single input and produces at most one output. When a process outputs, it stops taking steps.
The system is asynchronous, meaning there are no restrictions on the process schedule. In particular, any process may stop taking steps at any point in a run, which may be interpreted as crashing. An algorithm is wait-free when every process that takes sufficiently many steps produces an output, and it is bounded wait-free when there is a fixed constant such that no process takes more than steps before producing an output.
A process participates in a run when it takes at least one step, and a run is complete when all participating processes produce an output. An input assignment is a map from a subset of the processes to inputs, and, similarly, an output assignment is a map from a subset of the processes to outputs. A complete run determines an input assignment and an output assignment in the obvious way.
A task is a relation between input assignments and output assignments that have the same domain. An algorithm solves a task when, for each complete run, if the input assignment is in the domain of the task, then the output assignment is in the image of that input assignment. (Note that, since we only consider solving tasks and wait-free algorithms, and since a process can never tell whether another process that has not produced an output will take further steps, it suffices to place requirements on complete runs.)
Each process has a unique natural number called its process identifier. When processes are not anonymous, the algorithm may use this identifier. When processes are anonymous, we forbid the algorithm from using the process identifier.
As recently introduced by Taubenfeld [37], the shared registers may also be anonymous. In this case, each process is assigned an arbitrary permutation of the registers, which is unknown to the processes. When executes a read or write of a register , the register that is accessed is not but . If processes are anonymous, we preclude from consideration tasks that assign each process a unique input, as, in this case, each process can use its input as a unique identifier. When both processes and registers are anonymous, we say that the model is fully anonymous [36].
Note that solvability of a task for anonymous processes implies solvability for non-anonymous processes, and that solvability with anonymous registers implies solvability with non-anonymous registers.
Finally, the space complexity of a task in a given variant of the model (anonymous/non-anonymous processes, anonymous/non-anonymous memory, processes or an infinite number of processes) is the minimum number of registers needed to solve the task in the model variant.
3 For Every , There is a Task of Space Complexity
This section shows that, assuming either finitely or infinitely many non-anonymous processes, for every , there is a task of space complexity . This holds regardless of register anonymity. To show this, we define the -bounded lattice agreement task, for , and we show that:
-
-bounded lattice agreement is not wait-free solvable with fewer than registers, and
-
There is a wait-free algorithm (Algorithm 1) that solves -bounded lattice agreement using anonymous registers in a system of infinitely many non-anonymous processes.
Definition 1.
For every , the -bounded lattice-agreement task for processes is defined as follows. Processes receive no input, and each participating process outputs a set of process identifiers (possibly of cardinality greater than ), such that:
-
Validity. Each participating process outputs a set of participating processes.
-
Self-inclusion. Each process appears in its own output.
-
Containment. Every two outputs of cardinality at most are related by containment.
Note that, for , any algorithm that solves -bounded lattice agreement also solves -bounded lattice agreement, but not necessarily vice versa. Also note that, if there are processes, then -bounded lattice agreement is the same as the classic lattice-agreement task [5] on the lattice of sets of process identifiers.
3.1 Lower Bound: Registers Are Necessary
Theorem 2 (Space Complexity Lower Bound for k-Bounded Lattice Agreement).
For every integer , no read/write wait-free algorithm solves -bounded lattice agreement for processes using registers or fewer.
In a nutshell, to prove this theorem, we build a finite run at the end of which each register , , is about to be overwritten by a distinct process , process has not written thus far, and process has not taken any steps. Then, we schedule until it outputs. Next, we obliterate any trace that participated by scheduling the writes of . Finally, we let run until it outputs. To and , this run is indistinguishable from a run where the other did not participate. Thus must output a set not containing and must output a set not containing ; this violates the containment condition. A full proof appears in [19] and in the full version of this paper.
3.2 Upper Bound: Registers Are Sufficient
This section presents, for every , a wait-free algorithm that solves -bounded lattice agreement for infinitely many non-anonymous processes using anonymous registers. Pseudocode appears in Algorithm 1.
At a high level, the algorithm works as follows. Every process keeps track of the set of processes it has seen so far (local variable seen), and it eventually outputs this set. Until it determines it can output, each process executes the following loop in which it accesses a shared register array of registers:
-
1.
First, at line 10, writes to a shared register (indicated by the cyclic counter ) a triple consisting of its identifier, a locally unique sequence number (equal to the number of writes it has done so far), and the set of processes it has seen so far.
- 2.
-
3.
-
(a)
If has seen more than processes (including itself), outputs.
-
(b)
If ’s atomic snapshot did not succeed, goes back to line 13 to try again to obtain an atomic snapshot.
-
(c)
If ’s atomic snapshot succeeded and, in the snapshot, every shared register contains exactly the set of processes that has seen so far, then outputs.
-
(d)
Else, goes to the next iteration of its main loop (i.e. it jumps back to line 10).
-
(a)
To try to take an atomic snapshot, each process reads the whole shared array twice in a row, storing the first array read in the local array collect. A process determines that it obtained an atomic snapshot of the array if each register has the same value in both the first and second read. Because processes write their identifier and a sequence number that each process uses only once, no triple is written more than once; this guarantees that no write happened in between the last read at line 14 and the first read at line 17, and thus the collect array is an instantaneous copy of the shared array as it was between those two points in time. This well-known snapshot technique was first presented by Afek et al. [1].
The safety of the algorithm relies on the fact that, once a process obtains a snapshot in which every register in the shared array contains some process , because there are registers, as long as only other processes participate, the registers cannot all be overwritten and will forever remain in at least one register. Similar reasoning is used by Delporte-Gallet et al. [10] in their SWMR-emulation algorithm. See Appendix A for a rigorous proof.
Wait-freedom intuitively relies on the following facts: (1) the seen set of each process must eventually remain constant (as it can only grow and the process outputs when it reaches a size greater than ); (2) if a set of processes keep taking steps forever, the one with the smallest seen set must always eventually grow its seen set, or it would output, which contradicts (1). For lack of space, we provide a rigorous proof in the full version of this paper.
4 Space-Complexity Separates Anonymous From Non-Anonymous Memory
This section shows that, whether processes are anonymous or not, the binary adopt-commit task (Binary AC for short) has space complexity 3 when registers are non-anonymous, but it has space complexity when registers are anonymous. These results establish that there is a space-complexity separation between non-anonymous and anonymous registers.
Definition 3.
In the binary adopt-commit task, each process receives a bit (0 or 1) as input and must output a pair of the form or for some bit . When a process outputs , we say that commits , and when outputs , we say that adopts . Outputs must satisfy the following properties:
-
1.
Validity. If all participating processes have the same input , then they all commit , and
-
2.
Agreement. If a participating process commits a value , then every participating process either commits or adopts .
4.1 Binary AC Has Space Complexity 3 if Registers Are Non-anonymous
In this section, we present an algorithm that solves binary AC using 3 non-anonymous registers for infinitely many anonymous processes, and we show that this is optimal.
Pseudocode appears in Algorithm 2. Processes communicate using three shared registers , , and , all initially containing the value . Each process has two local variables: input, containing the input of the process, and output, eventually containing the output of the process. The algorithm unfolds as follows. Each process first announces its input by writing to register if it has input and to register if it has input (line 3). Then, checks if a different input has been announced (line 4). There are two cases.
First, if sees no different input, announces its intent to commit by writing its input to (line 11), and then checks again (line 12) whether a different input has been announced; if not, commits its input (line 13), and otherwise, adopts its input (line 15).
Second, if notices at line 4 a different input, then will not try to commit, and instead checks whether a process has declared its intent to commit in register (line 5); if so, then adopts the contents of register (line 6), and otherwise, adopts its input (line 8).
Theorem 4.
Algorithm 2 is a correct solution to adopt-commit.
The correctness of the algorithm rests on the following basic shared-memory property:
Property 1.
If and are two different shared registers, if a set of processes each write to then read from , if a disjoint set of processes each write to then read from , and if no other processes write to or , then either every member of reads a write by a member of , or vice versa.
The algorithm relies on Property 1 to ensure the following properties of adopt-commit:
-
1.
At most one value is committed. To see this, instantiate Property 1 with , being the set of processes with input , , and being the set of processes with input . By Property 1 and the algorithm, this implies that one of the two sets of processes will never write , and thus that at most one value is committed.
-
2.
If a process commits a value , then every process that adopts a value adopts . To see this, first note that, by the previous point, only the processes having input are at risk of not adopting . Next, instantiate Property 1 with , being the set of processes that write to , , and being the set of processes with input . By the algorithm, all processes that commit belong to and never read from , and, thus, by Property 1, every member of must read from .
Finally, it is easy to see that processes adopt or commit inputs of participating processes. ∎
Theorem 5 (Lower bound for solving adopt-commit using non-anonymous registers).
Solving binary adopt-commit wait-free for three or more processes requires at least three registers.
Proof.
Simple covering arguments. Assume, to the contrary, that binary can be solved for three processes with two registers. Let .
Claim 1.
A process must write before it terminates when it runs alone.
Proof of Claim 1.
If a process runs solo, it must commit; if it did not write, other processes would have no way to avoid adopting or committing a different value.
Claim 2.
The first write of processes with the same input must be to the same register, when each runs alone.
Proof of Claim 2.
Assume this is not the case. Let , , and have inputs , respectively, and suppose and make their first write to different registers. Run and until they are about to write. Before they write, run until it terminates; only sees itself, so it must commit . Let and each take one step so that the two registers are overwritten, and there is no trace left of . and must then commit . Contradiction.
Claim 3.
The first write of processes with different inputs must be to the same register, when each runs alone.
Proof of Claim 3.
Assume this is not the case. Let and have inputs and , respectively, and assume that and make their first write to different registers. After they write, let run to completion. For some value , either adopts or commits . Let have input . Now consider a new run, and let and run until they are about to write for the first time. At that point, run until it terminates; only sees itself, so it must commit . Let and each take one step so that the two registers are overwritten, and there is no trace left of . Now will either adopt or commit . Contradiction.
Claim 4.
When a process runs alone, it will not write to both registers.
Proof of Claim 4.
Assume this is not the case. Let , , and have inputs , respectively. First, run these three processes until they are ready to write for the first time. By Claim 1 and Claim 2, they are ready to write to the same register. Run until it is ready to write to the second register. Let take one step so that the register written by is overwritten, and there is no trace that or ever participated. Then run until it terminates; only sees itself, so it must commit . Next, let and each take one step so that the two registers are overwritten, and there is no trace of . Now let and run to completion; they both must commit . Contradiction.
We are now ready to complete the proof of the theorem. Assume and have inputs and , respectively. First, run both processes until they are about to write. By Claim 2, they are about to write to the same register. Next, run until it terminates; only sees itself, so it must commit . By Claim 3, writes to only one register. Next, let take one step so that the register written by is overwritten, and there is no trace of . Finally, run until it terminates; only sees itself, so it must commit . Contradiction.
4.2 Binary AC Has Space Complexity if Registers Are Anonymous
In this section, we show that binary AC has space complexity if registers are anonymous: First, we present a wait-free adopt-commit algorithm for processes using registers in the fully-anonymous model. Second, we show that a space complexity of is optimal if registers are anonymous (even if processes are non-anonymous).
The solution to binary AC using anonymous registers appears in Algorithm 3. The idea is to emulate the non-memory-anonymous algorithm of the previous section (Algorithm 2) in the fully-anonymous model by announcing inputs and intents to commit, not by directly writing to registers, but by using the lattice-agreement task.
In the lattice-agreement task, each participating process receives a set of values as input and must output a set of values such that:
-
1.
Every output is a union of input sets of participating processes,
-
2.
Each process outputs a set that contains its input set, and
-
3.
Every two output sets are related by containment.
To emulate Algorithm 2 using lattice agreement, each process announces its input by calling lattice agreement with a singleton set containing its input. It then uses the set returned by lattice agreement to check whether another input was announced. To announce its intent to commit, a process calls lattice agreement a second time as a fresh process, this time providing as input the set consisting of the previous lattice-agreement output and a tuple indicating its intent to commit its input. Again, it checks whether a conflicting input was announced by checking whether a conflicting input appears in the set returned by its second lattice-agreement invocation.
Theorem 6.
Algorithm 3 is a correct fully-anonymous implementation of adopt-commit.
Proof.
The algorithm works for the same reason as Algorithm 2, because lattice agreement gives us a property analogous to Property 1:
Property 2.
If and are two different elements, if each process in a set calls lattice agreement with a set containing , and if each process in a disjoint set calls lattice agreement with a set containing , then either every member of receives, in return, a set containing or every member of receives, in return, a set containing .
Using Property 2 instead of Property 1, we can repeat the correctness proof of Algorithm 2.
It now remains to implement lattice agreement for processes in the fully-anonymous model, including the ability for processes to call the algorithm twice as two different virtual processes. The algorithm appears in Algorithm 4. In order to use only registers, it assumes that a second call by a process provides an input that is a superset of the previous output of the process. Note that Algorithm 3 guarantees this is the case.
Algorithm 4 is similar to Algorithm 1: we have an array of registers (instead of in Algorithm 1) and each process repeatedly (a) writes the set of all inputs it has seen so far to one register selected round-robin (line 10) and then (b) attempts to obtain an atomic snapshot of the array (lines 13 to 21, as described below); stops and outputs the set of inputs it has seen so far when is able to obtain an atomic snapshot of the array such that each register contains exactly the set of inputs that has seen so far (line 25). Since ’s second invocation contains its previous output, there are only processes left that can obliterate ’s output. Since there are registers and processes have to read the whole array again after they write, ’s output will remain in at least one register, and the containment property of lattice agreement holds. It is easy to see that wait-freedom holds, as, contrary to the setting of Algorithm 1, there are only a fixed number of invocations.
Finally, we now explain how Algorithm 4 obtains atomic snapshots of the array. In Algorithm 1, each process attempts to obtain an atomic snapshot of the array using two successive reads of the whole array, which, if identical, indicate a successful atomic snapshot. This works because each write is unique, as each process includes its identifier and a unique sequence number. With anonymous processes, processes obviously cannot include a unique process identifier in their write, and two successive identical reads of the whole array no longer guarantee an atomic snapshot because the same value may be written by multiple processes (we have the famous “ABA problem”, as described e.g. in [28]). Luckily, a small change suffices to obtain atomic snapshots in the fully-anonymous model: as first observed by Ruppert and Guerraoui [21], obtaining identical reads of the whole register array guarantees an atomic snapshot, because, thanks to the sequence numbers, each value may be written at most times while the process reads. Thus, instead of reading the array twice and declaring that we have a snapshot if the reads are identical, we read the array times and declare that we have a snapshot if all the reads are identical.
Theorem 7 (Lower bound for anonymous registers).
When registers are anonymous, solving wait-free binary adopt-commit for processes requires at least registers.
Proof.
We use a simple covering argument. Assume, to the contrary, that it can be solved with fewer than anonymous registers. Let the input of be 0, and the input of all the other processes be 1. Run all processes with input 1 until each is ready to write for the first time, and arrange the assignment of the anonymous registers to the processes so that all of the registers are ready to be written by at least one of these processes. Run solo until it terminates; only sees itself, so it must output the pair . Let each of the other processes take one step so that all the registers are overwritten, and there is no trace that ever participated. Now, let all the processes run to completion, and, by definition, they all must output . Contradiction.
5 A Task Achieving Minimal Space Complexity in All Models
This section shows that there is a task that has space complexity 2 in all the models of the paper. This is the minimal non-trivial space complexity achievable. Indeed, no meaningful synchronization is possible with only one register, as we can always create a run in which each process obliterates any trace of other participating processes and then terminates.
Definition 8.
We define the contention detection task (abbreviated CD) as follows. Each participating process receives an input value (which may or may not be unique). Each participating process must produce an output that is the input of some participating process. Moreover, at most one participating process is such that (a) outputs its own input, and (b) no other participating process has the same input as .
For example, if participating processes receive unique inputs, then at most one process outputs its input. However, if, e.g., three processes , , and participate and and receive the same input , then all three processes may output their own input.
Theorem 9.
Contention detection has space complexity 2 in all four models of the paper.
Proof.
For the lower bound, it is easy to see that CD cannot be solved with just one register: schedule two processes until they are poised to write, then let one go and terminate, and finally let the other go and terminate. The processes do not learn about each other’s existence, and thus each must return its own input, which violates the specification of CD if their inputs are different.
For the upper bound, the algorithm of Algorithm 5 solves contention detection for arbitrarily many anonymous processes using two anonymous registers. To prove the correctness of the algorithm, assume, toward a contradiction, that there are two processes and such that outputs its own input , no other process has input , process outputs its own input , and no other process has input .
Remember that registers are anonymous: each access by a process to a register in fact accesses register , where is an unknown permutation of the registers.
First, note that neither nor outputs at line 6, and thus they both output at line 8. To see this, suppose toward a contradiction that outputs at line 6. Then outputs the contents of register . But has not written to , and thus it must output the input of another process. Since no other process has the same input as , we conclude that does not output its own input. This is a contradiction. The situation is similar for .
Next, suppose, without loss of generality, that executes line 8 after executes that same line. There are two cases: either or .
Suppose that . Then must execute line 8 before ’s first write at line 3, otherwise either or would not read its own input at line 8. But then must read a non- value at line 4 and thus output at line 6. This is a contradiction.
Suppose that . Then must execute its write at line 7 before writes at line 3 (otherwise cannot overwrite it and would read it). But then must have written at line 3 before reads at line 4, and thus must read a non- value at line 4. Thus outputs at line 6, which is a contradiction.
6 A Space-Complexity Separation Among Sub-Cases of Adopt-Commit
Section 4 presented tight space lower bounds for binary adopt-commit that reveal a space-complexity separation between anonymous and non-anonymous registers. This section continues our study of adopt-commit, this time finding a space-complexity separation (whether processes are anonymous or not) in non-anonymous memory between two variants of adopt-commit, -adopt-commit and -adopt-commit, which differ only in the range of values from which inputs may be drawn.
Definition 10.
For every integer and integer with , we consider the task of -valued adopt-commit with at most inputs, denoted -adopt-commit (in short -AC). This task is the adopt-commit task with an additional restriction on the possible combinations of inputs that may be received: Each process receives as input one of values drawn from the range . In other words, we restrict ourselves to input assignments that contain at most different values, each in the range .
Note that traditional adopt-commit, in which inputs come from an arbitrary set and processes may all receive different inputs, solves all -AC tasks.
Next, we show that -adopt-commit has strictly lower space complexity than -adopt-commit. We start by presenting Algorithm 6, which solves -adopt-commit.
Algorithm 6 is similar in principle to Algorithm 2: we have 3 shared registers, and processes use two of them to announce their input and the third to announce their intent to commit. However, since there are 3 possible input values instead of 2, it is no longer possible to statically reserve a unique register per input and an additional register for the commit value (we would need 4 registers in total). Nevertheless, we know that only 2 of the 3 values will be in play. The idea is thus to associate each register with a unique input value, knowing that after detecting which two input values and are present, we can use the remaining register, denoted , as the commit register to play a role analogous to register in Algorithm 2.
But where does a process that does not detect any other value, and thus cannot compute which register is the commit register, announce its intent to commit? The solution is to write its input value in all the registers. This, however, risks overwriting the announcement of a potential competing value. To avoid this problem, we organize the registers in a ring and instruct processes to write in the ring order, starting from the register assigned to their input value. This ensures that only the value that comes directly after the other value in the ring may be overwritten. In the case of adopt, giving priority to the non-overwritable value (see lines 28 to 31) ensures that, should that value commit, we will not adopt a contradictory value.
Theorem 11.
Algorithm 6 is a bounded wait-free solution to -adopt-commit.
Proof.
If all processes have the same input, then it is easy to see that all commit their input and we are done. So, assume that there are two different inputs . Let be the missing value (i.e., such that ). Note that , i.e., register is the commit register.
First, note that at most one value is ever written to the commit register . To see this, let (i.e. is the predecessor of in the ring) and let be the other input value. We have two cases. First, assume that a process with input first writes to register . Then did not find value in any register before writing to register . Thus, any process with input must still read register before writing to it; that read will return value and thus process will not proceed to registers and . Second, assume that a process with input first writes to register . This means that, when last read, register contained value and no process with input had written yet; therefore, any such process must read value and will never attempt to write to .
Next, observe that a process that commits must have written its input to register (because it writes its input to all registers in that case). Thus, because at most one value is ever written to register , every process that commits must commit the same value.
Next, when a process reaches line 25, if another process committed a value , then will find in register and adopt it. It remains to show that if adopts a value on lines 29 or 31, then no process later commits a different value. Note that, in this case, no process has written to register yet. Moreover, the value adopted by is never obliterated, because chooses the earlier value in the cyclic write order. Thus, any process that commits after adopts must first read ’s adopted value. Hence, commits ’s value.
Finally, since it has no loops, the algorithm is trivially bounded wait-free.
Next, we show that -adopt-commit has strictly higher space complexity than -adopt-commit:
Theorem 12.
No bounded wait-free algorithm solves -adopt-commit using only 3 non-anonymous registers in a system of infinitely many non-anonymous processes.
Proof.
Suppose, towards a contradiction, that there is a wait-free algorithm solving -AC using 3 non-anonymous registers for infinitely many non-anonymous processes.
First, note that we easily get a contradiction if some process never writes. Thus, we assume that every process writes at least once.
Next, note that, for each input value , there is a register such that there is an infinite set of processes such that, for every , if has input then, in a solo execution, ’s first write is to . Therefore, because there are 3 registers and 4 different input values, by the Pigeonhole Principle, there are two different input values and , a register , and two unbounded, disjoint sequences of processes and such that, for every :
-
if has input , then the first write of in a solo run is to register , and
-
if has input , then the first write of in a solo run is to register .
Next, let be a constant such that each process produces an output in at most of its own steps (which must exist, since the algorithm is bounded wait-free). Hence, each process reads at most times.
Now consider the executions in which the participating set consists of 3 processes , , and , each with input drawn from , and an additional processes from , each with input , and an additional processes from , each with input (so we have participating processes in total). Let the processes of and run until they are all poised on register , ready to perform their first write. Now let , , and run, but each time one of them, say , reads register : if has input , then arrange for a member of who has never written to write to just before ’s read; similarly, if has input , arrange for a member of who has never written to write to just before ’s read.
To , , and , such executions are indistinguishable from executions where only , , and participate and where, instead of reading , each process just behaves as if it read its input value, and where processes just skip writing . Conversely, it is easy to see that, for each such execution, there is an execution of the original algorithm with processes, as described above, that is indistinguishable to , , and . Thus we obtain an algorithm that solves the binary adopt-commit task for 3 processes using only 2 non-anonymous registers. This contradicts Theorem 5.
7 Related Work
There is a long list of works that study related notions of space complexity. They differ from this work in one or more aspects: they consider communication primitives other than MRMW registers (e.g., test-and-set objects), they consider progress conditions other than wait-freedom (e.g., obstruction-freedom), they consider problems that are not tasks (e.g., mutual exclusion), or they measure the size of registers rather than their number. We now give an overview of the most relevant results.
Space complexity as number of registers.
In one of the earliest results in the field, Burns and Lynch [7] show, using a so-called “covering argument”, that atomic read/write registers are necessary and sufficient for mutual exclusion among asynchronous processes.
A series of papers [18, 41, 20, 16] study the number of MRMW registers needed to solve consensus under variants of obstruction-freedom, culminating in a lower bound of registers [16] for nondeterministic solo-terminating consensus.
Other works generalize this line of inquiry to set-agreement. Delporte-Gallet et al. [11] and Bouzid et al. [6] give algorithms for -valued -obstruction-free -set agreement using registers. Ellen et al. [16] give a lower bound of registers needed to solve -valued -set agreement under -obstruction-freedom. Their proof relies on a novel simulation to reduce the lower bound to the impossibility of read/write wait-free -set agreement.
Ellen et al. [14] consider instructions, such as read, write, fetch-and-increment, test-and-set, write-max, etc., each of which can be applied to any register given as a parameter. Their results include upper and lower bounds on the number of registers required for solving obstruction-free -valued consensus among processes, for various sets of instructions (e.g., given read-max and write-max instructions, two registers are necessary and sufficient to solve obstruction-free -valued consensus among processes).
Two papers study the number of registers needed to solve problems when only read-write instructions are allowed during uncontended operations, but more powerful instructions are allowed if there is contention. Luchangco et al. [27] show that the wait-free CAS object needs only a constant number of registers. Capdevielle et al. [8] show that, if processes are anonymous, then the space complexity depends non-trivially on the number of processes and the maximal number of input values allowed.
Fatourou et al. [17] show that registers are necessary and sufficient for wait-free -valued atomic snapshot (which is not a task). Thus, instances of the -valued atomic snapshot problem form an infinite space hierarchy in the read/write wait-free model, similarly to the hierarchy of Section 3. However, it is not clear how this result could be turned into a result about tasks. Ellen et al. [13] and Helmi et al. [22] study the number of registers needed to implement wait-free and obstruction-free timestamp objects.
In a preamble to this paper, the same authors [19] propose the notion of a stranger-free task and show that their wait-free solution requires registers. They also show that -bounded lattice agreement is stranger-free for processes, and thus that it requires at least registers.
Space complexity as number of objects.
Jayanti et al. [24] study the number of base objects needed for non-blocking randomized implementations of higher-level objects, for some particular sets of objects that they define. Ovens studies the space complexity of consensus and set-agreement using base objects such as swap or test-and-set [32, 33, 30, 31].
Tasks solvable wait-free with fewer registers than processes.
The splitter task of Moir and Anderson [29] has a wait-free implementation for an unbounded number of processes using only two non-anonymous registers. Lamport [25] previously described a similar construction.
Aspnes and Ellen [4] study the step complexity of adopt-commit, but their work also contains implementations of tasks with a fixed number of registers. They implement a binary conflict detector for anonymous processes using 2 non-anonymous registers, and generalize to a -valued conflict detector using non-anonymous registers. They also implement adopt-commit using a conflict detector and 2 additional registers. This means 4 non-anonymous registers for binary adopt-commit and non-anonymous registers for -valued adopt-commit, which gives an upper bound of on the space complexity of -valued adopt-commit for any number of anonymous processes.
Register allocation.
As we have seen in this paper, a major difficulty when trying to solve a task for processes using fewer than shared read/write registers is that processes may overwrite each other. A similar difficulty arises even with or more registers if the registers are not a priori allocated to unique processes. Delporte-Gallet et al. [12] present a non-blocking algorithm that emulates pre-allocated registers using non-pre-allocated registers, and show that this is optimal. Subsequent work [10] presents an adaptive register-allocation algorithm for an unknown that uses a number of non-pre-allocated registers that is linear in the number of participating processes.
Anonymous memory.
Taubenfeld [37, 39] recently asked what coordination can be achieved, and how, if there is no a priori agreement among processes about the names (or numbering) of shared registers; in this case, we say that the registers are anonymous. An interesting phenomenon arising only with anonymous memory is that a problem may be solvable with some number of registers but not with registers. For example, Taubenfeld [39] shows that deadlock-free mutual exclusion for two processes is solvable with an odd number of registers but not with an even number of registers. Recent work [40, 37, 38] gives a number of impossibility results separating anonymous memory from non-anonymous memory, but none are for wait-free computation.
The fully-anonymous model, where both processes and registers are anonymous, was first investigated by Raynal and Taubenfeld [35, 36]. Losa and Gafni [26] propose a fully-anonymous lattice-agreement algorithm in this model; Algorithm 4 provides a simpler solution based on an idea of Guerraoui and Ruppert [21].
Register size.
In a recent paper, Delporte-Gallet et al. [9] investigate the distributed-computability implications of bounding not the number of registers but their size. Their results include the observation that 1-bit registers are universal for 1-resilient computation but not for wait-free computation. Ellen et al. [15] consider a read-modify-write object holding bits and study the solvability of the signal-detection problem depending on . Aksenov et al. and Anoprenko et al. study the implementation of queues and unique IDs, respectively, from bounded registers [2, 3].
8 Future Work
In Section 3, we have exhibited an infinite space-complexity hierarchy in the case of non-anonymous processes. Thus, the next questions to ask are whether there are infinite space-complexity hierarchies in the process-anonymous case and in the fully-anonymous case. Those questions remain open, but the paper and related work provide some initial clues.
With anonymous processes and non-anonymous registers, we have shown that CD has complexity two (Section 5) and binary adopt-commit has space complexity three (Section 4.1). In Section 6, we have shown that -adopt-commit is solvable with three registers but -adopt-commit is not. Aspnes and Ellen [4] implement -valued adopt-commit (i.e., -adopt-commit) using registers. This suggests an interesting space-complexity hierarchy among -adopt-commit tasks.
Under full anonymity, the -adopt-commit and -adopt-commit algorithms mentioned above do not work. However, we have shown that CD has space complexity two (Section 5) and that binary adopt-commit has space complexity (Section 4.2).
Finally, as shown by Taubenfeld [39], the mutual exclusion problem (which is not a task) for two processes is solvable for symmetric processes only with an odd number of anonymous registers. Thus, with anonymous memory, it is likely worthwhile to investigate space-complexity as a vector of natural numbers describing for which numbers of registers the task is solvable.
References
- [1] Yehuda Afek, Hagit Attiya, Danny Dolev, Eli Gafni, Michael Merritt, and Nir Shavit. Atomic snapshots of shared memory. Journal of the ACM, 40(4):873–890, September 1993. doi:10.1145/153724.153741.
- [2] Vitaly Aksenov, Nikita Koval, Petr Kuznetsov, and Anton Paramonov. Memory Bounds for Concurrent Bounded Queues. In Proceedings of the 29th ACM SIGPLAN Annual Symposium on Principles and Practice of Parallel Programming, PPoPP ’24, pages 188–199, New York, NY, USA, February 2024. Association for Computing Machinery. doi:10.1145/3627535.3638497.
- [3] Michael Anoprenko, Petr Kuznetsov, and Vitaly Aksenov. Brief Announcement: Optimal Construction of Unique Identifiers from Bounded Registers. In Proceedings of the ACM Symposium on Principles of Distributed Computing, PODC ’25, pages 62–65, New York, NY, USA, June 2025. Association for Computing Machinery. doi:10.1145/3732772.3733539.
- [4] James Aspnes and Faith Ellen. Tight Bounds for Adopt-Commit Objects. Theory of Computing Systems, 55(3):451–474, October 2014. doi:10.1007/s00224-013-9448-1.
- [5] Hagit Attiya, Maurice Herlihy, and Ophir Rachman. Atomic snapshots using lattice agreement. Distributed Computing, 8(3):121–132, March 1995. doi:10.1007/BF02242714.
- [6] Zohir Bouzid, Michel Raynal, and Pierre Sutra. Anonymous obstruction-free (n, k)-set agreement with $$n-k+1$$atomic read/write registers. Distributed Computing, 31(2):99–117, April 2018. doi:10.1007/s00446-017-0301-7.
- [7] J. E. Burns and N. A. Lynch. Bounds on Shared Memory for Mutual Exclusion. Information and Computation, 107(2):171–184, December 1993. doi:10.1006/inco.1993.1065.
- [8] Claire Capdevielle, Colette Johnen, Petr Kuznetsov, and Alessia Milani. On the Uncontended Complexity of Anonymous Consensus. In DROPS-IDN/v2/Document/10.4230/LIPIcs.OPODIS.2015.12. Schloss-Dagstuhl - Leibniz Zentrum für Informatik, 2016. doi:10.4230/LIPIcs.OPODIS.2015.12.
- [9] Carole Delporte-Gallet, Hugues Fauconnier, Pierre Fraigniaud, Sergio Rajsbaum, and Corentin Travers. The Computational Power of Distributed Shared-Memory Models with Bounded-Size Registers. In Proceedings of the 43rd ACM Symposium on Principles of Distributed Computing, PODC ’24, pages 310–320, New York, NY, USA, June 2024. Association for Computing Machinery. doi:10.1145/3662158.3662789.
- [10] Carole Delporte-Gallet, Hugues Fauconnier, Eli Gafni, and Leslie Lamport. Adaptive register allocation with a linear number of registers. In International Symposium on Distributed Computing, pages 269–283. Springer, 2013. doi:10.1007/978-3-642-41527-2_19.
- [11] Carole Delporte-Gallet, Hugues Fauconnier, Eli Gafni, and Sergio Rajsbaum. Black art: Obstruction-free k-set agreement with mwmr registers < proccesses. In Vincent Gramoli and Rachid Guerraoui, editors, Networked Systems - First International Conference, NETYS 2013, Marrakech, Morocco, May 2-4, 2013, Revised Selected Papers, volume 7853 of Lecture Notes in Computer Science, pages 28–41, Berlin, Heidelberg, 2013. Springer. doi:10.1007/978-3-642-40148-0_3.
- [12] Carole Delporte-Gallet, Hugues Fauconnier, Eli Gafni, and Sergio Rajsbaum. Linear Space Bootstrap Communication Schemes. In Davide Frey, Michel Raynal, Saswati Sarkar, Rudrapatna K. Shyamasundar, and Prasun Sinha, editors, Distributed Computing and Networking, pages 363–377, Berlin, Heidelberg, 2013. Springer. doi:10.1007/978-3-642-35668-1_25.
- [13] Faith Ellen, Panagiota Fatourou, and Eric Ruppert. The space complexity of unbounded timestamps. Distributed Computing, 21(2):103–115, July 2008. doi:10.1007/s00446-008-0060-6.
- [14] Faith Ellen, Rati Gelashvili, Nir Shavit, and Leqi Zhu. A complexity-based classification for multiprocessor synchronization. Distributed Computing, 33(2):125–144, April 2020. doi:10.1007/s00446-019-00361-3.
- [15] Faith Ellen, Rati Gelashvili, Philipp Woelfel, and Leqi Zhu. Space Lower Bounds for the Signal Detection Problem. In Rolf Niedermeier and Christophe Paul, editors, 36th International Symposium on Theoretical Aspects of Computer Science (STACS 2019), volume 126 of Leibniz International Proceedings in Informatics (LIPIcs), pages 26:1–26:13, Dagstuhl, Germany, 2019. Schloss Dagstuhl – Leibniz-Zentrum für Informatik. doi:10.4230/LIPIcs.STACS.2019.26.
- [16] Faith Ellen, Rati Gelashvili, and Leqi Zhu. Revisionist Simulations: A New Approach to Proving Space Lower Bounds. In Proceedings of the 2018 ACM Symposium on Principles of Distributed Computing, PODC ’18, pages 61–70, New York, NY, USA, July 2018. Association for Computing Machinery. doi:10.1145/3212734.3212749.
- [17] Panagiota Fatourou, Faith Fich, and Eric Ruppert. Space-optimal multi-writer snapshot objects are slow. In Proceedings of the Twenty-First Annual Symposium on Principles of Distributed Computing, PODC ’02, pages 13–20, New York, NY, USA, July 2002. Association for Computing Machinery. doi:10.1145/571825.571828.
- [18] Faith Fich, Maurice Herlihy, and Nir Shavit. On the space complexity of randomized synchronization. J. ACM, 45(5):843–862, September 1998. doi:10.1145/290179.290183.
- [19] Eli Gafni, Giuliano Losa, Michel Raynal, and Gadi Taubenfeld. Brief Announcement: Stranger-Free Tasks. In Proceedings of the ACM Symposium on Principles of Distributed Computing, PODC ’25, pages 203–206, New York, NY, USA, June 2025. Association for Computing Machinery. doi:10.1145/3732772.3733545.
- [20] Rati Gelashvili. On the optimal space complexity of consensus for anonymous processes. Distributed Computing, 31(4):317–326, August 2018. doi:10.1007/s00446-018-0331-9.
- [21] Rachid Guerraoui and Eric Ruppert. What Can Be Implemented Anonymously? Technical report, EPFL, 2004. URL: https://infoscience.epfl.ch/handle/20.500.14299/214730.
- [22] Maryam Helmi, Lisa Higham, Eduardo Pacheco, and Philipp Woelfel. The Space Complexity of Long-Lived and One-Shot Timestamp Implementations. J. ACM, 61(1):7:1–7:25, January 2014. doi:10.1145/2559904.
- [23] Maurice Herlihy. Wait-free Synchronization. ACM Transactions on Programming Languages and Systems, 13(1):124–149, January 1991. doi:10.1145/114005.102808.
- [24] Prasad Jayanti, King Tan, and Sam Toueg. Time and Space Lower Bounds for Nonblocking Implementations. SIAM Journal on Computing, 30(2):438–456, January 2000. doi:10.1137/S0097539797317299.
- [25] Leslie Lamport. A fast mutual exclusion algorithm. ACM Trans. Comput. Syst., 5(1):1–11, January 1987. doi:10.1145/7351.7352.
- [26] Giuliano Losa and Eli Gafni. Brief Announcement: Understanding Read-Write Wait-Free Coverings in the Fully-Anonymous Shared-Memory Model. In Proceedings of the 43rd ACM Symposium on Principles of Distributed Computing, PODC ’24, pages 465–468, New York, NY, USA, June 2024. Association for Computing Machinery. doi:10.1145/3662158.3662786.
- [27] Victor Luchangco, Mark Moir, and Nir Shavit. On the Uncontended Complexity of Consensus. In Faith Ellen Fich, editor, Distributed Computing, pages 45–59, Berlin, Heidelberg, 2003. Springer. doi:10.1007/978-3-540-39989-6_4.
- [28] Maged M. Michael and Michael L. Scott. Simple, fast, and practical non-blocking and blocking concurrent queue algorithms. In Proceedings of the Fifteenth Annual ACM Symposium on Principles of Distributed Computing - PODC ’96, pages 267–275, Philadelphia, Pennsylvania, United States, 1996. ACM Press. doi:10.1145/248052.248106.
- [29] Mark Moir and James H. Anderson. Wait-free algorithms for fast, long-lived renaming. Science of Computer Programming, 25(1):1–39, October 1995. doi:10.1016/0167-6423(95)00009-H.
- [30] Sean Ovens. The Space Complexity of Scannable Binary Objects. In Proceedings of the 2021 ACM Symposium on Principles of Distributed Computing, PODC’21, pages 509–519, New York, NY, USA, July 2021. Association for Computing Machinery. doi:10.1145/3465084.3467916.
- [31] Sean Ovens. The Space Complexity of Scannable Objects with Bounded Components. In Christian Scheideler, editor, 36th International Symposium on Distributed Computing (DISC 2022), volume 246 of Leibniz International Proceedings in Informatics (LIPIcs), pages 30:1–30:18, Dagstuhl, Germany, 2022. Schloss Dagstuhl – Leibniz-Zentrum für Informatik. doi:10.4230/LIPIcs.DISC.2022.30.
- [32] Sean Ovens. Brief Announcement: The Space Complexity of Set Agreement Using Swap. In Rotem Oshman, editor, 37th International Symposium on Distributed Computing (DISC 2023), volume 281 of Leibniz International Proceedings in Informatics (LIPIcs), pages 46:1–46:6, Dagstuhl, Germany, 2023. Schloss Dagstuhl – Leibniz-Zentrum für Informatik. doi:10.4230/LIPIcs.DISC.2023.46.
- [33] Sean Ovens. The Space Complexity of Consensus from Swap. J. ACM, 71(1):1:1–1:26, February 2024. doi:10.1145/3631390.
- [34] Michel Raynal. About Informatics, Distributed Computing, and Our Job: A Personal View. In Sergio Rajsbaum, Alkida Balliu, Joshua J. Daymude, and Dennis Olivetti, editors, Structural Information and Communication Complexity, pages 33–45, Cham, 2023. Springer Nature Switzerland. doi:10.1007/978-3-031-32733-9_3.
- [35] Michel Raynal and Gadi Taubenfeld. Mutual exclusion in fully anonymous shared memory systems. Information Processing Letters, 158:105938, June 2020. doi:10.1016/j.ipl.2020.105938.
- [36] Michel Raynal and Gadi Taubenfeld. Fully Anonymous Consensus and Set Agreement Algorithms. In Chryssis Georgiou and Rupak Majumdar, editors, Networked Systems, Lecture Notes in Computer Science, pages 314–328, Cham, 2021. Springer International Publishing. doi:10.1007/978-3-030-67087-0_20.
- [37] Gadi Taubenfeld. Coordination Without Prior Agreement. In Proceedings of the ACM Symposium on Principles of Distributed Computing, PODC ’17, pages 325–334, New York, NY, USA, July 2017. Association for Computing Machinery. doi:10.1145/3087801.3087807.
- [38] Gadi Taubenfeld. Set Agreement Power Is Not a Precise Characterization for Oblivious Deterministic Anonymous Objects. In Michele Flammini and Keren Censor-Hillel, editors, Structural Information and Communication Complexity, volume 11639, pages 293–308. Springer International Publishing, Cham, 2019. doi:10.1007/978-3-030-24922-9_20.
- [39] Gadi Taubenfeld. Anonymous Shared Memory. Journal of the ACM, 69(4):24:1–24:30, August 2022. doi:10.1145/3529752.
- [40] Gadi Taubenfeld. Memory-Anonymous Starvation-Free Mutual Exclusion: Possibility and Impossibility Results, September 2023. doi:10.48550/arXiv.2309.11337.
- [41] Leqi Zhu. A tight space bound for consensus. In Proceedings of the Forty-Eighth Annual ACM Symposium on Theory of Computing, STOC ’16, pages 345–350, New York, NY, USA, June 2016. Association for Computing Machinery. doi:10.1145/2897518.2897565.
Appendix A Proof of Safety of the Bounded Lattice-Agreement Algorithm
In this section, we prove that Algorithm 1 is a safe implementation of -bounded lattice agreement. To do so, we first, we need some terminology. We say that a shared register contains a process , written , when the seen component of contains . Similarly, contains a set of processes , written , when for every . We say that a process appears in the shared array when there is a register such that ; we say that a set of processes appears in the shared array when, for every , there is a register such that . We say that a process obtains a snapshot of the shared array when it reaches line 20 with its local snapshot variable set to true.
Lemma 13.
If a process obtains a snapshot, then, at some time between the time starts its preceding double collect and the time at which finishes it, the shared array has the same contents as ’s local collect array when it obtains the snapshot.
Proof.
Since no array value is written more than once, two identical collects guarantee that no write happened in between.
Lemma 14.
Consider a process that terminates and outputs a set of identifiers of cardinality at most (i.e. outputs at line 23). There is a time before outputs such that, from onwards, either there is a shared register such that or at least processes appear in the shared array.
Proof.
By Lemma 13, there is a time before outputs such that, at time , all registers contain exactly . Now consider the state predicate asserting that, for each shared register such that , we can associate a unique process such that and wrote (anywhere) after time . Note that is suffices to that holds at all times after , which we now do using strong induction.
First, note that the property holds at time since every register contains exactly . Next, suppose that the property holds from time to time and that a process takes a step at time . We now show by case analysis that holds again after ’s step.
-
1.
If writes a superset of , then still holds with the same mapping as before the step.
-
2.
Suppose that writes a set such that .
-
(a)
Suppose that, before ’s step, for some .
-
i.
If writes to , then still holds, with the same mapping as before the step, since processes always write at least their own identifier.
-
ii.
Suppose that writes to . By the induction hypothesis, this is at least the second write of after , and thus obtains a snapshot between and , which, by Lemma 13, is equal to the contents of memory at some time between and . Hence, by the induction hypothesis, either (a) sees in its snapshot or (b) sees at least (the number of registers) processes in its snapshot who all wrote between and . Since writes where , case (a) is not possible and thus sees at least processes who all wrote after . Hence, contains at least processes who all wrote after . Since there are registers, among the processes above there exists a process such that, for every , . Letting and keeping the mapping otherwise unchanged, we establish that holds again.
-
i.
-
(b)
Suppose that, for every register such that , , and that writes to a register . Then we can simply update the mapping with , and holds again.
-
(a)
-
3.
If reads, then is trivially preserved.
Lemma 15.
The algorithm satisfies the containment property.
Proof.
We must show that if a process outputs a set and a process outputs a set , and both and are of cardinality at most , then and are related by containment (that is, either or ). This is immediate from Lemma 14 and the fact that each process that returns a set of cardinality at most returns values appearing in an atomic snapshot of the shared array.
