CP — Concurrent Programming 3. Safety and Synchronization Prof. O. Nierstrasz Wintersemester 2005 / 2006.

Slides:



Advertisements
Similar presentations
Operating Systems Semaphores II
Advertisements

Operating Systems: Monitors 1 Monitors (C.A.R. Hoare) higher level construct than semaphores a package of grouped procedures, variables and data i.e. object.
Concurrent programming for dummies (and smart people too) Tim Harris & Keir Fraser.
– R 7 :: 1 – 0024 Spring 2010 Parallel Programming 0024 Recitation Week 7 Spring Semester 2010.
Practice Session 7 Synchronization Liveness Deadlock Starvation Livelock Guarded Methods Model Thread Timing Busy Wait Sleep and Check Wait and Notify.
Ch 7 B.
Concurrency Important and difficult (Ada slides copied from Ed Schonberg)
Ch. 7 Process Synchronization (1/2) I Background F Producer - Consumer process :  Compiler, Assembler, Loader, · · · · · · F Bounded buffer.
Silberschatz, Galvin and Gagne ©2007 Operating System Concepts with Java – 7 th Edition, Nov 15, 2006 Chapter 6 (a): Synchronization.
Chapter 6 Process Synchronization Bernard Chen Spring 2007.
Chapter 6: Process Synchronization
Background Concurrent access to shared data can lead to inconsistencies Maintaining data consistency among cooperating processes is critical What is wrong.
5.1 Silberschatz, Galvin and Gagne ©2009 Operating System Concepts with Java – 8 th Edition Chapter 5: CPU Scheduling.
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
Process Synchronization. Module 6: Process Synchronization Background The Critical-Section Problem Peterson’s Solution Synchronization Hardware Semaphores.
12. Common Errors, a few Puzzles. © O. Nierstrasz P2 — Common Errors, a few Puzzles 12.2 Common Errors, a few Puzzles Sources  Cay Horstmann, Computing.
5. Liveness and Guarded Methods Prof. O. Nierstrasz Selected material © Magee and Kramer.
3. Safety and Synchronization Prof. O. Nierstrasz Selected material © Magee and Kramer.
ESE Einführung in Software Engineering 7. Modeling Behaviour Prof. O. Nierstrasz.
CS 5704 Fall 00 1 Monitors in Java Model and Examples.
CP — Concurrent Programming 5. Safety and Liveness Properties Prof. O. Nierstrasz Wintersemester 2005 / 2006.
CP — Concurrent Programming 8. Liveness and Asynchrony Prof. O. Nierstrasz Wintersemester 2005 / 2006.
10. Petri Nets Prof. O. Nierstrasz. Roadmap  Definition: —places, transitions, inputs, outputs —firing enabled transitions  Modelling: —concurrency.
12. Common Errors, a few Puzzles. © O. Nierstrasz P2 — Common Errors, a few Puzzles 12.2 Common Errors, a few Puzzles Overview  Common errors … —Typical.
ESE Einführung in Software Engineering N. XXX Prof. O. Nierstrasz Fall Semester 2009.
© Oscar Nierstrasz ST — Smalltalk Basics 2.1 Change sets  Make sure your changes are logged to a new change set.
Avishai Wool lecture Introduction to Systems Programming Lecture 4 Inter-Process / Inter-Thread Communication.
CP — Concurrent Programming 1. Introduction Prof. O. Nierstrasz Wintersemester 2005 / 2006.
CP — Concurrent Programming 2. Java and Concurrency Prof. O. Nierstrasz Wintersemester 2005 / 2006.
ESE Einführung in Software Engineering X. CHAPTER Prof. O. Nierstrasz Wintersemester 2005 / 2006.
Chapter 6: Process Synchronization. Outline Background Critical-Section Problem Peterson’s Solution Synchronization Hardware Semaphores Classic Problems.
CP — Concurrent Programming 12. Petri Nets Prof. O. Nierstrasz Wintersemester 2005 / 2006.
Metamodeling Seminar X. CHAPTER Prof. O. Nierstrasz Spring Semester 2008.
Silberschatz, Galvin and Gagne ©2007 Operating System Concepts with Java – 7 th Edition, Nov 15, 2006 Process Synchronization (Or The “Joys” of Concurrent.
© Oscar Nierstrasz ST — Smalltalk Basics 2.1 Change sets  Make sure your changes are logged to a new change set.
ESE Einführung in Software Engineering X. CHAPTER Prof. O. Nierstrasz Wintersemester 2005 / 2006.
N. XXX Prof. O. Nierstrasz Thanks to Jens Palsberg and Tony Hosking for their kind permission to reuse and adapt the CS132 and CS502 lecture notes.
7. Fixed Points. © O. Nierstrasz PS — Fixed Points 7.2 Roadmap Overview  Representing Numbers  Recursion and the Fixed-Point Combinator  The typed.
12. Common Errors, a few Puzzles. © O. Nierstrasz P2 — Common Errors, a few Puzzles 12.2 Common Errors, a few Puzzles Sources  Cay Horstmann, Computing.
Synchronization in Java Fawzi Emad Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
7. Liveness and Asynchrony Prof. O. Nierstrasz. Roadmap  Asynchronous invocations  Simple Relays —Direct invocations —Thread-based messages —Command-based.
3. Safety and Synchronization Prof. O. Nierstrasz Selected material © Magee and Kramer.
OORPT Object-Oriented Reengineering Patterns and Techniques X. CHAPTER Prof. O. Nierstrasz.
CP — Concurrent Programming X. CHAPTER Prof. O. Nierstrasz Wintersemester 2005 / 2006.
Concurrency - 1 Tasking Concurrent Programming Declaration, creation, activation, termination Synchronization and communication Time and delays conditional.
12. eToys. © O. Nierstrasz PS — eToys 12.2 Denotational Semantics Overview:  … References:  …
Threads II. Review A thread is a single flow of control through a program Java is multithreaded—several threads may be executing “simultaneously” If you.
Concurrency: shared objects & mutual exclusion1 ©Magee/Kramer 2 nd Edition Chapter 4 Shared Objects & Mutual Exclusion.
Concurrency Recitation – 2/24 Nisarg Raval Slides by Prof. Landon Cox.
Parallel Processing (CS526) Spring 2012(Week 8).  Thread Status.  Synchronization in Shared Memory Programming(Java threads ) ◦ Locks ◦ Barriars.
6.3 Peterson’s Solution The two processes share two variables: Int turn; Boolean flag[2] The variable turn indicates whose turn it is to enter the critical.
Semaphores, Locks and Monitors By Samah Ibrahim And Dena Missak.
CSC321 Concurrent Programming: §5 Monitors 1 Section 5 Monitors.
Concurrency: Mutual Exclusion and Synchronization Chapter 5.
1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.
1 Concurrency: Mutual Exclusion and Synchronization Chapter 5.
ICS 313: Programming Language Theory Chapter 13: Concurrency.
Threads Doing Several Things at Once. Threads n What are Threads? n Two Ways to Obtain a New Thread n The Lifecycle of a Thread n Four Kinds of Thread.
Threads Eivind J. Nordby University of Karlstad Inst. for Information Technology Dept. of Computer Science.
CS399 New Beginnings Jonathan Walpole. 2 Concurrent Programming & Synchronization Primitives.
1 Condition Variables CS 241 Prof. Brighten Godfrey March 16, 2012 University of Illinois.
CP — Concurrent Programming 6. Liveness and Guarded Methods Prof. O. Nierstrasz Wintersemester 2005 / 2006.
Comunication&Synchronization threads 1 Programación Concurrente Benemérita Universidad Autónoma de Puebla Facultad de Ciencias de la Computación Comunicación.
CSC321 §8 Implementing FSP Models in Java 1 Section 8 Implementing FSP Models in Java.
Multithreading / Concurrency
Background on the need for Synchronization
Thread Synchronization
Critical section problem
CSE 153 Design of Operating Systems Winter 19
CS333 Intro to Operating Systems
Presentation transcript:

CP — Concurrent Programming 3. Safety and Synchronization Prof. O. Nierstrasz Wintersemester 2005 / 2006

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.2 Safety and Synchronization Overview  Modelling interaction in FSP  Safety — synchronizing critical sections —Locking for atomicity —The busy-wait mutual exclusion protocol  Conditional synchronization —Slots in FSP —wait(), notify() and notifyAll() —Slots in Java Selected material © Magee and Kramer

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.3 Modelling interaction — shared actions Actions that are common between two processes are shared and can be used to model process interaction:  Unshared actions may be arbitrarily interleaved  Shared actions occur simultaneously for all participants What are the states of the LTS? The traces? What are the states of the LTS? The traces? MAKER= ( make -> ready -> MAKER ). USER= ( ready -> use -> USER ). ||MAKER_USER = ( MAKER || USER ). MAKER= ( make -> ready -> MAKER ). USER= ( ready -> use -> USER ). ||MAKER_USER = ( MAKER || USER ). 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.4 Modelling interaction — handshake A handshake is an action that signals acknowledgement What are the states and traces of the LTS? 01 MAKERv2= ( make -> ready -> used -> MAKERv2 ). USERv2= ( ready -> use -> used -> USERv2 ). ||MAKER_USERv2 = ( MAKERv2 || USERv2 ). MAKERv2= ( make -> ready -> used -> MAKERv2 ). USERv2= ( ready -> use -> used -> USERv2 ). ||MAKER_USERv2 = ( MAKERv2 || USERv2 ).

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.5 Safety problems Objects must only be accessed when they are in a consistent state, formalized by a class invariant. Each method assumes the class invariant holds when it starts, and it re-establishes it when done. If methods interleave arbitrarily, an inconsistent state may be accessed, and the object may be left in a “dirty” state. Where shared resources are updated may be a critical section. m1 m2 m3 m4 m5 Consistent states ?!

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.6 Atomicity and interference Consider the two processes: How can these processes interfere? { x = 0 } AInc:x := x+1 BInc:x := x+1 { x = ? } { x = 0 } AInc:x := x+1 BInc:x := x+1 { x = ? }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.7 Atomic actions Individual reads and writes may be atomic actions: const N=3 range T=0..N Var=Var[0], Var[u:T]=( read[u]-> Var[u] | write[v:T]-> Var[v] ). set VarAlpha = { read[T], write[T] } Inc =(read[v:0..N-1] ->write[v+1] ->STOP )+VarAlpha. const N=3 range T=0..N Var=Var[0], Var[u:T]=( read[u]-> Var[u] | write[v:T]-> Var[v] ). set VarAlpha = { read[T], write[T] } Inc =(read[v:0..N-1] ->write[v+1] ->STOP )+VarAlpha.

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.8 Sequential behaviour A single sequential thread requires no synchronization: ||SeqInc = (Var||Inc). 01

read[1] read[2] read[0] write[0] write[2] write[3] Var Inc write[1] write[2] write[3] read[1] write[1] write[0] read[0] write[1] write[2] write[3] read[0] / write[0]

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.10 Concurrent behaviour Without synchronization, concurrent threads may interfere: ||ParInc = ({a,b}::Var || a:Inc || b:Inc). 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.11 Locking Locks are used to make a critical section atomic: LOCK=( acquire -> release -> LOCK ). INC=(acquire ->read[v:0..N-1] ->write[v+1] ->release ->STOP) +VarAlpha. LOCK=( acquire -> release -> LOCK ). INC=(acquire ->read[v:0..N-1] ->write[v+1] ->release ->STOP) +VarAlpha. 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.12 Synchronization Processes can synchronize critical sections by sharing a lock: ||ParInc2 = ({a,b}::VAR || {a,b}::LOCK || a:INC || b:INC). 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.13 Synchronization in Java Java Threads also synchronize using locks: is just convenient syntax for: Every object has a lock, and Threads may use them to synchronize with each other. synchronized T m() { // method body } synchronized T m() { // method body } T m() { synchronized (this) { // method body } T m() { synchronized (this) { // method body }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.14 Busy-Wait Mutual Exclusion Protocol P1 sets enter1 := true when it wants to enter its CS, but sets turn := “P2” to yield priority to P2 Is this protocol correct? Is it fair? Deadlock-free? process P1 loop enter1 := true turn := “P2” while enter2 and turn = “P2” do skip Critical Section enter1 := false Non-critical Section end process P1 loop enter1 := true turn := “P2” while enter2 and turn = “P2” do skip Critical Section enter1 := false Non-critical Section end process P2 loop enter2 := true turn := “P1” while enter1 and turn = “P1” do skip Critical Section enter2 := false Non-critical Section end process P2 loop enter2 := true turn := “P1” while enter1 and turn = “P1” do skip Critical Section enter2 := false Non-critical Section end

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.15 Atomic read and write We can model integer and boolean variables as processes with atomic read and write actions: range T = 1..2 Var = Var[1], Var[u:T] = ( read[u] -> Var[u] | write[v:T]-> Var[v]). set Bool = {true,false} BOOL(Init='false) = BOOL[Init], BOOL[b:Bool] = ( is[b]-> BOOL[b] | setTo[x:Bool]-> BOOL[x]). range T = 1..2 Var = Var[1], Var[u:T] = ( read[u] -> Var[u] | write[v:T]-> Var[v]). set Bool = {true,false} BOOL(Init='false) = BOOL[Init], BOOL[b:Bool] = ( is[b]-> BOOL[b] | setTo[x:Bool]-> BOOL[x]).

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.16 Modelling the busy-wait protocol Each process performs two actions in its CS: P1 = ( enter1.setTo['true] -> turn.write[2] -> Gd1), Gd1 = ( enter2.is['false] -> CS1 | enter2.is['true] -> ( turn.read[1] -> CS1 | turn.read[2] -> Gd1)), CS1 = ( a -> b -> enter1.setTo['false] -> P1). P1 = ( enter1.setTo['true] -> turn.write[2] -> Gd1), Gd1 = ( enter2.is['false] -> CS1 | enter2.is['true] -> ( turn.read[1] -> CS1 | turn.read[2] -> Gd1)), CS1 = ( a -> b -> enter1.setTo['false] -> P1). P2 = ( enter2.setTo['true] -> turn.write[1] -> Gd2), Gd2 = ( enter1.is['false] -> CS2 | enter1.is['true] -> ( turn.read[2] -> CS2 | turn.read[1] -> Gd2)), CS2 = ( c -> d -> enter2.setTo['false] -> P2). P2 = ( enter2.setTo['true] -> turn.write[1] -> Gd2), Gd2 = ( enter1.is['false] -> CS2 | enter1.is['true] -> ( turn.read[2] -> CS2 | turn.read[1] -> Gd2)), CS2 = ( c -> d -> enter2.setTo['false] -> P2). ||BusyWait =

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.17 Busy-wait composition Very pretty, but how do we know there are no errors?! 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.18 Checking for errors We can check for errors by composing our system with an agent that moves to the ERROR state if atomicity is violated: What happens if we break the protocol? Ok=( a -> ( c -> ERROR | b -> Ok ) | c -> ( a -> ERROR | d -> Ok)). ||BusyWaitOK = (enter1:BOOL||enter2:BOOL||turn:Var||P1||P2||Ok). Ok=( a -> ( c -> ERROR | b -> Ok ) | c -> ( a -> ERROR | d -> Ok)). ||BusyWaitOK = (enter1:BOOL||enter2:BOOL||turn:Var||P1||P2||Ok). 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.19 Conditional synchronization A lock delays an acquire request if it is already locked: Similarly, a one-slot buffer delays a put request if it is full and delays a get request if it is empty: LOCK =( acquire -> release -> LOCK ). const N = 2 Slot =( put[v:0..N] ->get[v] ->Slot ). const N = 2 Slot =( put[v:0..N] ->get[v] ->Slot ).

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.20 Producer/Consumer composition Producer = ( put[0] -> put[1] -> put[2] -> Producer ). Consumer = ( get[x:0..N] -> Consumer ). ||Chain =( Producer || Slot || Consumer ) Producer = ( put[0] -> put[1] -> put[2] -> Producer ). Consumer = ( get[x:0..N] -> Consumer ). ||Chain =( Producer || Slot || Consumer ) 01

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.21 Wait and notify A Java object whose methods are all synchronized behaves like a monitor Within a synchronized method or block:  wait() suspends the current thread, releasing the lock  notify() wakes up one thread waiting on that object  notifyAll() wakes up all threads waiting on that object Outside of a synchronized block, wait() and notify() will raise an IllegalMonitorStateException Always use notifyAll() unless you are sure it doesn’t matter which thread you wake up!

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.22 Slot (put) class Slot implements Buffer { private Object slotVal;// initially null public synchronized void put(Object val) { while (slotVal != null) { try { wait(); } // become NotRunnable catch (InterruptedException e) { } } slotVal = val; notifyAll(); // make waiting threads Runnable return; } … class Slot implements Buffer { private Object slotVal;// initially null public synchronized void put(Object val) { while (slotVal != null) { try { wait(); } // become NotRunnable catch (InterruptedException e) { } } slotVal = val; notifyAll(); // make waiting threads Runnable return; } … interface Buffer { public void put(Object val); public Object get(); } interface Buffer { public void put(Object val); public Object get(); }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.23 Slot (get) … public synchronized Object get() { Object rval; while (slotVal == null) { try { wait(); } catch (InterruptedException e) { } } rval = slotVal; slotVal = null; notifyAll(); return rval; } … public synchronized Object get() { Object rval; while (slotVal == null) { try { wait(); } catch (InterruptedException e) { } } rval = slotVal; slotVal = null; notifyAll(); return rval; }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.24 Active objects abstract class ActiveObject extends Thread { protected int count_; ActiveObject(String name, int count) { super(name); count_ = count; } public void run() { int i; for (i=1;i<=count_;i++) { this.action(i); this. randomSleep(); } protected abstract void action(int n); protected void randomSleep() { … } } abstract class ActiveObject extends Thread { protected int count_; ActiveObject(String name, int count) { super(name); count_ = count; } public void run() { int i; for (i=1;i<=count_;i++) { this.action(i); this. randomSleep(); } protected abstract void action(int n); protected void randomSleep() { … } } An active object has a thread of its own.

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.25 Producer in Java The Producer puts _count messages to the slot: class Producer extends ActiveObject { protected Buffer slot_; protected String wares_; Producer(String name, int count, Buffer slot, String wares) { super(name, count); slot_ = slot; wares_ = wares; } protected void action(int n) { String message; message = wares_ + "(" + String.valueOf(n) + ")"; slot_.put(message); System.out.println(getName() + " put " + message); } class Producer extends ActiveObject { protected Buffer slot_; protected String wares_; Producer(String name, int count, Buffer slot, String wares) { super(name, count); slot_ = slot; wares_ = wares; } protected void action(int n) { String message; message = wares_ + "(" + String.valueOf(n) + ")"; slot_.put(message); System.out.println(getName() + " put " + message); }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.26 Consumer in Java... and the Consumer gets them: class Consumer extends ActiveObject { protected Buffer slot_; Consumer(String name, int count, Buffer slot) { super(name, count); slot_ = slot; } protected void action(int n) { String message; message = (String) slot_.get(); System.out.println(getName() + " got " + message); } class Consumer extends ActiveObject { protected Buffer slot_; Consumer(String name, int count, Buffer slot) { super(name, count); slot_ = slot; } protected void action(int n) { String message; message = (String) slot_.get(); System.out.println(getName() + " got " + message); }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.27 Composing Producers and Consumers Multiple producers and consumers may share the buffer: Peter put apple (1) Carla got apple (1) Paula put orange(1) Cris got orange(1) Patricia put banana(1) Carla got banana(1) Peter put apple (2) Cris got apple (2) Patricia put banana(2) Carla got banana(2) Peter put apple (3) Cris got apple (3) Paula put orange(2) Carla got orange(2) Patricia put banana(3) Cris got banana(3) Peter put apple (4) Cris got apple (4) Peter put apple (5) Carla got apple (5) Paula put orange(3) Cris got orange(3) Patricia put banana(4) Cris got banana(4) Patricia put banana(5) Cris got banana(5) Paula put orange(4) Cris got orange(4) Paula put orange(5) Cris got orange(5) Peter put apple (1) Carla got apple (1) Paula put orange(1) Cris got orange(1) Patricia put banana(1) Carla got banana(1) Peter put apple (2) Cris got apple (2) Patricia put banana(2) Carla got banana(2) Peter put apple (3) Cris got apple (3) Paula put orange(2) Carla got orange(2) Patricia put banana(3) Cris got banana(3) Peter put apple (4) Cris got apple (4) Peter put apple (5) Carla got apple (5) Paula put orange(3) Cris got orange(3) Patricia put banana(4) Cris got banana(4) Patricia put banana(5) Cris got banana(5) Paula put orange(4) Cris got orange(4) Paula put orange(5) Cris got orange(5) public static void ProducerConsumerDemo() { Buffer slot = new Slot(); new Producer("Peter", "apple ", slot, count).start(); new Producer("Paula", "orange", slot, count).start(); new Producer("Patricia", "banana", slot, count).start(); new Consumer("Carla", slot, count).start(); new Consumer("Cris", slot, 2*count).start(); } public static void ProducerConsumerDemo() { Buffer slot = new Slot(); new Producer("Peter", "apple ", slot, count).start(); new Producer("Paula", "orange", slot, count).start(); new Producer("Patricia", "banana", slot, count).start(); new Consumer("Carla", slot, count).start(); new Consumer("Cris", slot, 2*count).start(); }

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.28 What you should know!  How do you model interaction with FSP?  What is a critical section? What is critical about it?  Why don’t sequential programs need synchronization?  How do locks address safety problems?  What primitives do you need to implement the busy-wait mutex protocol?  How can you use FSP to check for safety violations?  What happens if you call wait or notify outside a synchronized method or block?  When is it safe to use notifyAll()?

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.29 Can you answer these questions?  What is an example of an invariant that might be violated by interfering, concurrent threads?  What constitute atomic actions in Java?  Can you ensure safety in concurrent programs without using locks?  When should you use synchronize(this) rather than synchronize(someObject)?  Is the busy-wait mutex protocol fair? Deadlock-free?  How would you implement a Lock class in Java?  Why is the Java Slot class so much more complex than the FSP Slot specification?

© Oscar Nierstrasz CP — Safety and Synchronization CP 3.30 License > Attribution-ShareAlike 2.5 You are free: to copy, distribute, display, and perform the work to make derivative works to make commercial use of the work Under the following conditions: Attribution. You must attribute the work in the manner specified by the author or licensor. Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. For any reuse or distribution, you must make clear to others the license terms of this work. Any of these conditions can be waived if you get permission from the copyright holder. Your fair use and other rights are in no way affected by the above. Attribution-ShareAlike 2.5 You are free: to copy, distribute, display, and perform the work to make derivative works to make commercial use of the work Under the following conditions: Attribution. You must attribute the work in the manner specified by the author or licensor. Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. For any reuse or distribution, you must make clear to others the license terms of this work. Any of these conditions can be waived if you get permission from the copyright holder. Your fair use and other rights are in no way affected by the above.