Presentation is loading. Please wait.

Presentation is loading. Please wait.

Foundations of Shared Memory

Similar presentations


Presentation on theme: "Foundations of Shared Memory"— Presentation transcript:

1 Foundations of Shared Memory
Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit This chapter begins to provide the mathematical foundations for shared memory computation.

2 Fundamentals What is the weakest form of communication that supports mutual exclusion? What is the weakest shared object that allows shared-memory computation? Before we can start looking for practical algorithms to solve interesting problems, we need to understand what can and cannot be done on a multiprocessor. If something can’t be done, then it is prudent not to waste time doing it, and if something can be done in principle, even if we don’t know how to do it efficiently, then that is a good place to expend our energy. The natural place to start is to ask what is the weakest kind of communication or synchronization that we can use to do useful work? © 2007 Herlihy & Shavit

3 Alan Turing Helped us understand what is and is not computable on a sequential machine. Still best model available The foundations of sequential computing were established in the 1930s by Alan Turing and Alonzo Church, who independently formulated what has come to be known as the Church-Turing Thesis: anything that can be computed, can be computed by a Turing Machine, (or equivalently, by Church's Lambda Calculus). Any problem that cannot be solved by a Turing Machine (such as deciding whether a program halts on any input) is universally considered to be unsolvable by any kind of practical computing device. The Turing Thesis is a thesis, not a theorem, because the notion of ``what is computable'' can never be defined in a precise, mathematically rigorous way. Nevertheless, just about everyone believes it. © 2007 Herlihy & Shavit

4 Reads and Writes Infinite tape
Turing Machine Finite State Controller Reads and Writes Infinite tape 1 1 The classical theory of sequential computing proceeds in stages. It starts with finite-state automata, moves on to push-down automata, and culminates in Turing Machines. A Turing machine is an idealized model of computation, consisting of a finite-state controller and an infinite tape. It is safe to say that anything you can’t do on a Turing Machine is something you can’t do period. If you can devise a Turing machine program to do something, it doesn’t mean you can do it in a practical sense, but it gives you a place to start working on the problem. © 2007 Herlihy & Shavit

5 Turing Computability 1 1 Mathematical model of computation
1 1 Mathematical model of computation What is (and is not) computable Efficiency (mostly) irrelevant The classical theory of sequential computing is (for the most part) not concerned with efficiency: to show that a problem is computable, it is enough to show that it can be solved by a Turing Machine. There is little incentive to make such a Turing Machine efficient, because a Turing Machine is not a practical means of computation. This is a feature, not a bug. © 2007 Herlihy & Shavit

6 Shared-Memory Computability?
10011 Mathematical model of concurrent computation What is (and is not) concurrently computable Efficiency (mostly) irrelevant In the same way, we make little attempt to make our initial constructions efficient. We are interested in understanding whether such constructions exist, and how they work, but they are not intended to be a practical model for computation, so we prefer easy-to-understand but inefficient constructions over complicated but efficient ones. © 2007 Herlihy & Shavit

7 Foundations of Shared Memory
To understand modern multiprocessors we need to ask some basic questions … A shared-memory computation consists of multiple threads, each of which is a sequential program in its own right. These threads communicate by calling methods of objects that reside in a shared memory. Threads are asynchronous, meaning that they run at different speeds, and any thread can grind to a halt for an unpredictable duration at any time. This notion of asynchrony reflects the realities of modern multiprocessor architectures, where threads delays are unpredictable, ranging from microseconds (cache misses), to milliseconds (page faults) to seconds (scheduling interruptions). © 2007 Herlihy & Shavit

8 Foundations of Shared Memory
To understand modern multiprocessors we need to ask some basic questions … What is the weakest useful form of shared memory? The first question to ask is what is the weakest useful form of shared memory. Not because we want to save money by buying the least amount of machinery, like a standard transmission and manual windows on an automobile, but because this way we can figure out what is essential to getting the job done and what is useful to enhance efficiency, convenience, and so on. © 2007 Herlihy & Shavit

9 Foundations of Shared Memory
To understand modern multiprocessors we need to ask some basic questions … What is the weakest useful form of shared memory? What can it do? Paradoxically, perhaps, once we have identified the weakest useful model of concurrent computation, the next question is how far can we go with it? For example, in sequential computability, we can decide that finite state machines are useful, and we can use them, say to parse arithmetic expressions, control traffic lights, and do other simple tasks. © 2007 Herlihy & Shavit

10 Foundations of Shared Memory
To understand modern multiprocessors we need to ask some basic questions … What is the weakest useful form of shared memory? What can it do? What can’t it do? It is also extremely important to figure out what you can’t do with something. What are the limits? If we want to add new features to an architecture, are they there to make things faster or more convenient, or do they really add some kind of computational power, giving us the ability to do something we couldn’t do before. We will see that there are a lot of interesting and rather surprising things to say about what can and cannot be accomplished using various forms of synchronization. © 2007 Herlihy & Shavit

11 * Register 10011 Holds a (binary) value
In this chapter we start with the simplest form of shared-memory computation: concurrent threads apply simple read and write operations to shared variables, called registers for historical reasons. We will start with very simple registers, and we will see how to use them to construct a series of more complex registers. * A memory location: name is historical © 2007 Herlihy & Shavit

12 Register 10011 10011 Can be read © 2007 Herlihy & Shavit
A register’s value can be read by a thread. © 2007 Herlihy & Shavit

13 Register 01100 10011 Can be written © 2007 Herlihy & Shavit
Or a register can write a new value. © 2007 Herlihy & Shavit

14 Registers public interface Register<T> { public T read();
public void write(T v); } An m-valued register is one that can assume M values, and as an important special case, a two-valued register is called a Boolean register. For ease of presentation, register values are shown as integers, but they could be any kind of object (including references to other objects). © 2007 Herlihy & Shavit

15 (usually Boolean or m-bit Integer)
Registers public interface Register<T> { public T read(); public void write(T v); } Type of register (usually Boolean or m-bit Integer) An m-valued register is one that can assume M values, and as an important special case, a two-valued register is called a Boolean register. For ease of presentation, register values are shown as integers, but they could be any kind of object (including references to other objects). © 2007 Herlihy & Shavit

16 Single-Reader/Single-Writer Register
10011 01100 10011 One important distinction is how many threads can access a register. The simplest kind of register is used to communicate between two threads. © 2007 Herlihy & Shavit

17 Multi-Reader/Single-Writer Register
10011 01100 10011 It is also common to use a register to allow one thread to announce something to multiple threads via a multi-reader single-writer register. © 2007 Herlihy & Shavit

18 Multi-Reader/Multi-Writer Register
mumble 10011 10011 mumble 01010 10011 mumble The most general kind of register is a multi-reader multi-writer register that can be read or written by any number of threads. 11011 © 2007 Herlihy & Shavit

19 Jargon Watch SRSW MRSW MRMW Single-reader single-writer
Multi-reader single-writer MRMW Multi-reader multi-writer We use the following acronyms to make these distinctions in a compact way. © 2007 Herlihy & Shavit

20 OK if reads and writes don’t overlap
Safe Register OK if reads and writes don’t overlap write(1001) read(1001) A single-writer, multi-reader register implementation is safe if a read call that does not overlap a write call returns the value written by the most recent write call. (2) © 2007 Herlihy & Shavit

21 Some valid value if reads and writes do overlap
Safe Register Some valid value if reads and writes do overlap write(1001) read(????) $*&v Otherwise, if a read call overlaps a write call, then the read call may return any value within the register's allowed range of values (for example, 0 to M-1 for an M-valued register). For an enumerated type, say {clubs,spades,hearts,dimonds}, this register can’t return the value 1001… 0000 1001 1111 © 2007 Herlihy & Shavit

22 Regular Register Single Writer Readers return:
Old value if no overlap (safe) Old or one of new values if overlap A regular} register is a single-writer, multi-reader register where writes do not happen atomically. Instead, while the write call is in progress, the new value may ``flicker'' on and off before finally replacing the older value. More precisely, A regular register is safe}. If a read call overlaps the i-th write call, then the read call may return either the i-th or (i-1)-th value. © 2007 Herlihy & Shavit

23 Regular or Not? write(0) write(1) read(1) read(0)
Here’s a quick test for your intuition. Is this register history regular or not? © 2007 Herlihy & Shavit

24 Regular or Not? write(0) write(1) read(1) read(0)
Notice that the read that returns 1 overlaps the write call that writes 1, so this is regular so far. Overlap: returns new value © 2007 Herlihy & Shavit

25 Regular or Not? write(0) write(1) read(0) Overlap: returns old value
Here, too, the read that returns zero overlaps the write that wrote 1, so this history is regular. The way to think about this is that while the write of 1 is going on, the value is flickering between 0 and 1, and each read samples the value at some instant while it is running. Overlap: returns old value © 2007 Herlihy & Shavit

26 Regular or Not? regular write(0) write(1) read(1) read(0)
© 2007 Herlihy & Shavit

27 Regular ≠ Linearizable
write(0) write(1) read(1) read(0) explain this! Let us denote a register implementation that is linearizable to a sequential safe register as a linearizable register. Note that any linearizable register history is regular, but not vice-versa. Here is why the regular history we just looked at is not linearizable. write(1) already happened © 2007 Herlihy & Shavit

28 Linearizable to sequential safe register
Atomic Register write(1001) write(1010) read(1010) read(1001) read(1010) An atomic register is one that is linearizable to a sequential safe register. For registers, atomic is synonymous with linearizable, but we use a different term in this one case to remain consistent with the published literature. Linearizable to sequential safe register © 2007 Herlihy & Shavit

29 Atomic Register write(1001) write(1010) read(1010) read(1001)
© 2007 Herlihy & Shavit

30 Register Space MRMW MRSW M-valued Boolean SRSW Safe Regular Atomic
The space of registers can be divided into three dimensions, where the number of readers and writers is one dimension, the register size is another, and the strength of the correctness condition is a third. Safe Regular Atomic © 2007 Herlihy & Shavit

31 Weakest Register 1 1 Single writer Single reader Safe Boolean register
1 This is the quark of the register world. We can’t really think of anything weaker that is useful, so we will see how far we can get starting here. Safe Boolean register © 2007 Herlihy & Shavit

32 Get correct reading if not during state transition
Weakest Register Single writer Single reader flipflop 1 1 Get correct reading if not during state transition © 2007 Herlihy & Shavit

33 Foundations of the field
Results From SRSW safe Boolean register All the other registers Mutual exclusion But not everything! Consensus hierarchy Foundations of the field As we will see, can’t do everything with resgisters, but lets see how far we can actually go… The really cool stuff … (2) © 2007 Herlihy & Shavit

34 Locking within Registers
Not interesting to rely on mutual exclusion in register constructions We want registers to implement mutual exclusion! No fun to use mutual exclusion to implement itself! © 2007 Herlihy & Shavit

35 Wait-Free Implementations
Definition: An object implementation is wait-free if every method call completes in a finite number of steps No mutual exclusion Thread could halt in critical section Build mutual exclusion from registers © 2007 Herlihy & Shavit

36 Road Map SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit

37 Road Map Next SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Next © 2007 Herlihy & Shavit

38 Register Names public class SafeBoolMRSWRegister
implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } (3) © 2007 Herlihy & Shavit

39 Register Names property public class SafeBoolMRSWRegister
implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } property (3) © 2007 Herlihy & Shavit

40 Register Names property Size matters public class SafeBoolMRSWRegister
implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } property Size matters (3) © 2007 Herlihy & Shavit

41 How many readers & writers?
Register Names public class SafeBoolMRSWRegister implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } How many readers & writers? property type (3) © 2007 Herlihy & Shavit

42 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements Register<Boolean> { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} (2) © 2007 Herlihy & Shavit

43 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} Each thread has own safe SRSW register (2) © 2007 Herlihy & Shavit

44 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} write method (2) © 2007 Herlihy & Shavit

45 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} Write each thread’s register one at a time (2) © 2007 Herlihy & Shavit

46 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} read method (2) © 2007 Herlihy & Shavit

47 Safe Boolean MRSW from Safe Boolean SRSW
public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} Read my own register (2) © 2007 Herlihy & Shavit

48 Safe Boolean MRSW from Safe Boolean SRSW
1 1 1 1 0 or 1 Still OK to read 0 or 1 if concurrent with a write. 1 © 2007 Herlihy & Shavit

49 Q: Safe Multi-Valued MRSW Safe Multi-Valued SRSW?
1 1 1011 1000 Yes, it works! 1011 Any value in range Ask students if the same construction works if we have multi-valued registers…the answer is yes since if the write is concurrent with a read on some register then a valid value in the register’s range will be returned. 1000 1000 © 2007 Herlihy & Shavit

50 Road Map Questions? SRSW safe Boolean MRSW safe Boolean
MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot Questions? © 2007 Herlihy & Shavit

51 Road Map Next SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Next © 2007 Herlihy & Shavit

52 Regular Boolean MRSW from Safe Boolean MRSW
Safe register can return 0 or 1 even if the same value is written 1 Regular: if it changed, OK to read 0 or 1 Regular: But only old value if not changed 1 Still OK to read 0 or 1 if concurrent with a write because it a Boolean register and ) and 1 are in any case the old and the new if the value did change. But if the value did not change, then we must return the old value in a regular register even if there was a concurrent write. © 2007 Herlihy & Shavit

53 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean> { private boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); (2) © 2007 Herlihy & Shavit

54 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); Last bit this thread wrote (OK, we’re cheating here on Java syntax) (2) © 2007 Herlihy & Shavit

55 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); Actual value (2) © 2007 Herlihy & Shavit

56 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); Is new value different from last value I wrote? (2) © 2007 Herlihy & Shavit

57 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); If so, change it (otherwise don’t!) (2) © 2007 Herlihy & Shavit

58 Regular Boolean MRSW from Safe Boolean MRSW
public class RegBoolMRSWRegister implements Register<Boolean>{ threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); Overlap? No Overlap? No problem either Boolean value works (2) © 2007 Herlihy & Shavit

59 Regular Multi-Valued MRSW from Safe Multi-Valued MRSW?
Safe register can return value in range other than old or new when value changes 1 Multi-valued Regular register can return only old or new when value changes! 1 0101 No, it does not work! This is just a question to ask students to clarify the protocol. Ask students if the same construction works if we have multi-valued registers…It shows them that the reason the earlier construction with a Boolean register worked is because Boolean means that in the concurrent case you can get only 0 or 1. Here this construction breaks down in the concurrent case. © 2007 Herlihy & Shavit

60 Road Map Questions? SRSW safe Boolean MRSW safe Boolean
MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot Questions? © 2007 Herlihy & Shavit

61 Road Map Next SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Next © 2007 Herlihy & Shavit

62 MRSW Regular M-valued from MRSW Regular Boolean
public class RegMRSWRegister implements Register{ RegBoolMRSWRegister[M] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} © 2007 Herlihy & Shavit

63 MRSW Regular M-valued from MRSW Regular Boolean
public class RegMRSWRegister implements Register{ RegBoolMRSWRegister[M] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} Unary representation: bit[i] means value i © 2007 Herlihy & Shavit

64 MRSW Regular M-valued from MRSW Regular Boolean
public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} Set bit x (1) © 2007 Herlihy & Shavit

65 MRSW Regular M-valued from MRSW Regular Boolean
public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} Clear bits from higher to lower (1) © 2007 Herlihy & Shavit

66 MRSW Regular M-valued from MRSW Regular Boolean
public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} Scan from lower to higher & return first bit set (1) © 2007 Herlihy & Shavit

67 Writing M-Valued 1 1 0 1 2 3 4 5 6 7 Write 5 Initially 0
1 1 The value 5 is written by writing a 1 in the fifth array location and then zeroing out all other lower locations. © 2007 Herlihy & Shavit

68 Writing M-Valued 5 1 1 0 1 2 3 4 5 6 7 Write 5 © 2007 Herlihy & Shavit
1 1 5 Only when the last 0 written erases the bit indicating the old value, can the reader advance and find the new value 5. Can explain to students what happens when the old value is 6 or 7, that is, in a higher place than the value 5 that was written. © 2007 Herlihy & Shavit

69 Road Map Questions? SRSW safe Boolean MRSW safe Boolean
MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot Questions? © 2007 Herlihy & Shavit

70 Road Map SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit

71 Road Map (Slight Detour)
SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot SWSW Atomic We will take a slight detour. This is because its harder to implement MR atomic from MR regular, so lets do this SR first. © 2007 Herlihy & Shavit

72 SRSW Atomic From SRSW Regular
Regular writer Regular reader 1234 5678 1234 Instead of 5678… Concurrent Reading The problem in this construction could be that a reader of a regular register will read the old value instead of the new. When is this a problem? When is this a problem? © 2007 Herlihy & Shavit

73 SRSW Atomic From SRSW Regular
Regular writer Regular reader 1234 5678 5678 Same as Atomic Initially 1234 Reg write(5678) Reg read(5678) time © 2007 Herlihy & Shavit

74 SRSW Atomic From SRSW Regular
Regular writer Regular reader 1234 5678 1234 Same as Atomic Instead of 5678… Initially 1234 Reg write(5678) Reg read(1234) time © 2007 Herlihy & Shavit

75 SRSW Atomic From SRSW Regular
Regular writer Regular reader 1234 5678 1234 not Atomic! Instead of 5678… Initially 1234 Reg write(5678) The problem happens when the (single) reader has several reads that overlap the same write. In this case we run into trouble because if a later read sees a value earlier than a value of an earlier read this cannot be linearized. Reg read(5678) Reg read(1234) time Write 5678 happened © 2007 Herlihy & Shavit

76 Timestamped Values 1:45 1234 2:00 5678 2:00 5678
Reader saves last read (value,stamp) and returns new value only if higher stamp Writer writes value and stamp together A thread overcomes the problem by remembering the highest timestamp it read and never returning a new value that has a timestamp lower than what it already read. © 2007 Herlihy & Shavit

77 SRSW Atomic From SRSW Regular
writer reader 1234 1:45 5678 2:00 1: Less than 2: So stick with 5678 Same as Atomic 1:45 1234 Reg write(2: ) In this example the later read of a REGULAR register can return 1: , but the reader will not return this value because the value it remembered from the earlier read is 2: , that is, has a higher timestamp. read(2: ) read(1: ) > time old = 2:00 5678 © 2007 Herlihy & Shavit

78 Atomic Single Reader to Atomic Multi-Reader
stamp value 1:45 1234 1:45 1234 One per reader 1:45 1234 1:45 1234 © 2007 Herlihy & Shavit

79 Another Scenario Writer starts write… stamp value 2:00 5678 1:45 1234
© 2007 Herlihy & Shavit

80 Another Scenario 2:00, 5678 zzz… reader reads stamp value 2:00 5678
later reader 1:45 1234 1:45 1234 1:45 1234 1: A second reader is completely non-overlapping. Yellow was completely after blue but read earlier value…not linearizable! © 2007 Herlihy & Shavit

81 Multi-Reader Redux One per thread 1 2 3 1:45 1234 1:45 1234 1:45 1234
© 2007 Herlihy & Shavit

82 Multi-Reader Redux Writer writes column… 2:00, 5678 reader reads row 1
3 2:00 5678 1:45 1234 1:45 1234 1:45 1234 1 2:00 5678 1:45 1234 1:45 1234 1:45 1234 2 2:00 5678 1:45 1234 1:45 1234 1:45 1234 3 The problem is that an earlier read can read a value 5678 and a read that follows it completely in time will not see this value because the writer is slow. The solution is to have the readers always tell other readers what they have read. © 2007 Herlihy & Shavit

83 zzz…after second write
2:00, 5678 Multi-Reader Redux zzz…after second write reader writes column to notify others of what it read 1 2 1 2 3 2:00 5678 1:45 1234 2:00 5678 1:45 1234 1:45 1234 1 2:00 5678 1:45 1234 2:00 5678 1:45 1234 1:45 1234 2 1:45 1234 2:00 5678 1:45 1234 1:45 1234 3 Here is how an earlier Blue reader in column 2 will tell a later Yellow reader in column 3 that even though the writer did not write yet to column 3, the value 5678 has been read. It does so by writing its column, so it is effectively playing the role of a writer. Now if the Blue reader completed, then it must have written its column, and thus the yellow reader must see its value. Yellow reader will read new value in column written by earlier Blue reader © 2007 Herlihy & Shavit

84 Can’t Yellow Miss Blue’s Update? … Only if Readers Overlap…
1:45 1234 write(2: ) read(2: ) read(1: ) The students might be confused here, why can’t it be that the yellow reader will miss the writes of the Blue reader updating its column. The point is that this can only happen if the blue reader has not finished its read and has an overlap with the Yellow reader, in which case as the Timeline shows, its OK for Yellow to return the old value 1234. In which case its OK to read 1234 time © 2007 Herlihy & Shavit

85 Bad Case Only When Readers Don’t Overlap
1:45 1234 write(2: ) read(2: ) read(2: ) In which case Blue will complete writing 2: to its column time © 2007 Herlihy & Shavit

86 Road Map SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Next © 2007 Herlihy & Shavit

87 Multi-Writer Atomic From Multi-Reader Atomic
stamp value 1:45 1234 Each writer reads all then writes Max+1 to its register Readers read all and take max (Lexicographic like Bakery) 1:45 1234 2:00 5678 1:45 1234 1:45 1234 2:15 XYZW The algorithm works just like the doorway of the bakery, with each label having an added value field. The idea is that the threads each write a new timestamp by reading all timestamps and writing the value together with the associated timestamp. To read a thread goes through all the values and picks the one with the highest timestamp. Max is 2:15, return XYZW © 2007 Herlihy & Shavit

88 Atomic Execution Means its Linearizable
write(1) Read(max= 2) write(4) write(2) write(3) Read(max = 3) Read (max = 1) write(2) Read(max = 4) time time (4) © 2007 Herlihy & Shavit

89 Linearization Points time time write(1) Read(max= 2) write(4) write(2)
© 2007 Herlihy & Shavit

90 Linearization Points Look at Writes First time time write(1) write(4)
© 2007 Herlihy & Shavit

91 Order writes by TimeStamp
Linearization Points Order writes by TimeStamp write(1) write(4) write(2) write(3) Notice that ordering by the timestamps works because later writes will have strictly greater stamps.Concurrent writes can be ordered by ID if they have the same stamp, we don’t care. write(2) time time (4) © 2007 Herlihy & Shavit

92 Order reads by max stamp read
Linearization Points Order reads by max stamp read write(1) Read(max= 2) write(4) write(2) write(3) Read(max = 3) Read (max = 1) write(2) Read(max = 4) time time (4) © 2007 Herlihy & Shavit

93 Order reads by max stamp read
Linearization Points Order reads by max stamp read write(1) Read(max= 2) write(4) write(2) write(3) Read(max = 3) Read (max = 1) Reads are ordered so that each falls right after the write whose timestamp it read as MAXIMAL. This works because reads will never read things from the past or future, and it can never be the case that for two reads one completely after the other, the latter will read an earlier timestamp, because the higher timestamp must have been written already when it started the later read. write(2) Read(max = 4) time time (4) © 2007 Herlihy & Shavit

94 Linearization Points The linearization point depends on the execution (not a line in the code)! write(1) Read(max= 2) write(4) write(2) write(3) Read(max = 3) Read (max = 1) write(2) Read(max = 4) time time (4) © 2007 Herlihy & Shavit

95 Road Map SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Questions? © 2007 Herlihy & Shavit

96 Road Map SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean
MRSW atomic MRMW atomic Atomic snapshot Next © 2007 Herlihy & Shavit

97 Atomic Snapshot update scan © 2007 Herlihy & Shavit
Snapshots are scans of memory while updates are ongoing. As in a concurrent debugger or a backup procedure that does not “stop the world” to get an instantaneous view of memory. © 2007 Herlihy & Shavit

98 Atomic Snapshot Array of SWMR atomic registers
Take instantaneous snapshot of all Generalizes to MRMW registers … © 2007 Herlihy & Shavit

99 Snapshot Interface public interface Snapshot {
public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit

100 Snapshot Interface Thread i writes v to its register
public interface Snapshot { public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit

101 Instantaneous snapshot of all theads’ registers
Snapshot Interface Instantaneous snapshot of all theads’ registers public interface Snapshot { public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit

102 Atomic Snapshot Collect Problem Read values one at a time
Incompatible concurrent collects Result not linearizable © 2007 Herlihy & Shavit

103 Clean Collects Clean Collect Collect during which nothing changed
Can we make it happen? Can we detect it? © 2007 Herlihy & Shavit

104 Simple Snapshot = Put increasing labels on each entry Collect twice
If both agree, We’re done Otherwise, Try again Collect1 Collect2 1 22 7 13 18 12 1 22 7 13 18 12 = If none of the labels (timestamps) changed, then there was a point, after the end of the first collect, and before the start of the next collect, in which none of the registers were written to. The values collected correspond to the values that were all together in memory at that point in time. © 2007 Herlihy & Shavit

105 Simple Snapshot: Update
public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } (1) © 2007 Herlihy & Shavit

106 Simple Snapshot: Update
public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } One single-writer register per thread (1) © 2007 Herlihy & Shavit

107 Simple Snapshot: Update
public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } Write each time with higher label (1) © 2007 Herlihy & Shavit

108 Simple Snapshot: Collect
private LabeledValue[] collect() { LabeledValue[] copy = new LabeledValue[n]; for (int j = 0; j < n; j++) copy[j] = this.register[j].read(); return copy; } (1) © 2007 Herlihy & Shavit

109 Simple Snapshot private LabeledValue[] collect() {
LabeledValue[] copy = new LabeledValue[n]; for (int j = 0; j < n; j++) copy[j] = this.register[j].read(); return copy; } Just read each register into array (1) © 2007 Herlihy & Shavit

110 Simple Snapshot: Scan public int[] scan() {
LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} (1) © 2007 Herlihy & Shavit

111 Simple Snapshot: Scan Collect once public int[] scan() {
LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} Collect once (1) © 2007 Herlihy & Shavit

112 Simple Snapshot: Scan Collect once Collect twice public int[] scan() {
LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} Collect once Collect twice (1) © 2007 Herlihy & Shavit

113 Simple Snapshot: Scan Collect once Collect twice
public int[] scan() { LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} Collect once Collect twice On mismatch, try again (1) © 2007 Herlihy & Shavit

114 Simple Snapshot: Scan Collect once Collect twice
public int[] scan() { LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} Collect once Collect twice On match, return values (1) © 2007 Herlihy & Shavit

115 Simple Snapshot Linearizable Update is wait-free But Scan can starve
No unbounded loops But Scan can starve If interrupted by concurrent update © 2007 Herlihy & Shavit

116 Wait-Free Snapshot Add a scan before every update
Write resulting snapshot together with update value If scan is continuously interrupted by updates, scan can take the update’s snapshot © 2007 Herlihy & Shavit

117 Wait-free Snapshot ≠ If A’s scan observes that B moved
twice, then B completed an update while A’s scan was in progress 26 24 12 Collect Update B time © 2007 Herlihy & Shavit

118 Wait-free Snapshot ≠ A B time Collect 26 24 12 Update
© 2007 Herlihy & Shavit

119 Wait-free Snapshot ≠ A B time 26 24 12 Collect Scan Write Update
© 2007 Herlihy & Shavit

120 Wait-free Snapshot B’s 1st update must have written during 1st collect 26 24 12 Collect A Scan B Write Scan Write So A can steal result of B’s scan Update So scan of B’s second update must be within interval of A’s scan time © 2007 Herlihy & Shavit

121 Wait-free Snapshot ≠ A B But no guarantee that scan
26 24 12 Collect A Scan B Write Scan Write But no guarantee that scan of B’s 1st update can be used… Why? time © 2007 Herlihy & Shavit

122 Once is not Enough ≠ A B Why can’t A steal result of B’s scan
Collect 26 24 12 Collect A 26 24 12 B Update Scan Write Why can’t A steal result of B’s scan Update Because another update might have interfered before the scan time © 2007 Herlihy & Shavit

123 Someone Must Move Twice
26 24 12 Collect Update B time If we collect n times…some thread Must move twice (Pigeon hole) © 2007 Herlihy & Shavit

124 So some thread must have had clean collect
Scan is Wait-free scan At most n-1 depth update scan update So some thread must have had clean collect Each scan gets a clean collect or is interrupted, taking that thread’s scan. The scan of the interrupting thread Could also have been interrupted. This can however happen only n-1 times after which the are no more threads that can inturrupt. Hence the scan is wait-free. scan © 2007 Herlihy & Shavit

125 Wait-Free Snapshot Label
public class SnapValue { public int label; public int value; public int[] snap; } (2) © 2007 Herlihy & Shavit

126 Wait-Free Snapshot Label
public class SnapValue { public int label; public int value; public int[] snap; } Counter incremented with each snapshot (2) © 2007 Herlihy & Shavit

127 Wait-Free Snapshot Label
public class SnapValue { public int label; public int value; public int[] snap; } Actual value (2) © 2007 Herlihy & Shavit

128 Wait-Free Snapshot Label
public class SnapValue { public int label; public int value; public int[] snap; } most recent snapshot (2) © 2007 Herlihy & Shavit

129 Wait-Free Snapshot Label
…00 label Last snapshot value (3) © 2007 Herlihy & Shavit

130 Wait-free Update public void update(int value) {
int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); } (2) © 2007 Herlihy & Shavit

131 Wait-free Scan Take scan public void update(int value) {
int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); } Take scan (2) © 2007 Herlihy & Shavit

132 Wait-free Scan Take scan Label value with scan
public void update(int value) { int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); } Take scan Label value with scan (2) © 2007 Herlihy & Shavit

133 Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy;
boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { }} return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit

134 Wait-free Scan Keep track of who moved public int[] scan() {
SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { }} return getValues(newCopy); }}} Keep track of who moved (2) © 2007 Herlihy & Shavit

135 Repeated double collect
Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { }} return getValues(newCopy); }}} Repeated double collect (2) © 2007 Herlihy & Shavit

136 If mismatch detected…lets expand here…
Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { }} return getValues(newCopy); }}} If mismatch detected…lets expand here… (2) © 2007 Herlihy & Shavit

137 Mismatch Detected if (oldCopy[j].label != newCopy[j].label) {
if (moved[j]) { // second move return newCopy[j].snap; } else { moved[j] = true; oldCopy = newCopy; continue collect; }}} return getValues(newCopy); (2) © 2007 Herlihy & Shavit

138 If thread moved twice, just steal its second snapshot
Mismatch Detected if (oldCopy[j].label != newCopy[j].label) { if (moved[j]) { return newCopy[j].snap; } else { moved[j] = true; oldCopy = newCopy; continue collect; }}} return getValues(newCopy); If thread moved twice, just steal its second snapshot (2) © 2007 Herlihy & Shavit

139 Remember that thread moved
Mismatch Detected if (oldCopy[j].label != newCopy[j].label) { if (moved[j]) { // second move return newCopy[j].snap; } else { moved[j] = true; oldCopy = newCopy; continue collect; }}} return getValues(newCopy); Remember that thread moved (2) © 2007 Herlihy & Shavit

140 Observations Uses unbounded counters Assumes SWMR registers
can be replaced with 2 bits Assumes SWMR registers for labels can be extended to MRMW © 2007 Herlihy & Shavit

141 Summary We saw we could implement MRMW multi valued snapshot objects
From SRSW binary safe registers (simple flipflops) But what is the next step to attempt with read-write registers? © 2007 Herlihy & Shavit

142 Grand Challenge Snapshot means Write any one array element
Read multiple array elements © 2007 Herlihy & Shavit

143 atomic writes to multiple
Grand Challenge What about atomic writes to multiple locations? Writes to 0 and 1 Write many and snapshot Writes to 1 and 2 © 2007 Herlihy & Shavit

144 Art of Multiprocessor Programming
          This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License. You are free: to Share — to copy, distribute and transmit the work to Remix — to adapt the work Under the following conditions: Attribution. You must attribute the work to “The Art of Multiprocessor Programming” (but not in any way that suggests that the authors endorse you or your use of the work). Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license. For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to Any of the above conditions can be waived if you get permission from the copyright holder. Nothing in this license impairs or restricts the author's moral rights. Art of Multiprocessor Programming


Download ppt "Foundations of Shared Memory"

Similar presentations


Ads by Google