120 likes | 204 Views
Exceptions and side-effects in atomic blocks. Tim Harris. Atomic blocks. void put(int val) { atomic (!this.full) { this.full = true; this.val = val; } }. int get() { int result; atomic (this.full) { this.full = false; return this.val; } }.
E N D
Exceptions and side-effectsin atomic blocks Tim Harris
Atomic blocks void put(int val) { atomic (!this.full) { this.full = true; this.val = val; } } int get() { int result; atomic (this.full) { this.full = false; return this.val; } } • Basic syntax: ‘atomic (cond) { statements; }’ • Block until the condition is true… • …then execute the statements (doing all this as a single atomic step) • The statements can access fields & local variables, invoke methods, instantiate objects etc.
Atomic blocks (ii) General principle in single-threaded code: • atomic (E) { S }behaves the same as{E;S} • after blocking until a state in whichEis known to yieldtrue The compiler and VM are responsible for making this work well in multi-threaded systems: • first implementation used a software transactional memory • memory accesses in E and S remain thread-private • most non-conflicting operations can commit in parallel
Atomic blocks (iii) • A motivating (and stylized!) example: void serverLoop(ServerSocket s) { while (true) { Socket c = s.acceptConnection(); Thread t = new Thread() { public void run() { atomic { dealWithClient(c); } } } } • Try to deal with non-conflicting client requests concurrently • If something goes wrong (e.g. client triggers DivisionByZero) then try to contain failure • atomic means “all or nothing”
Option I: put it back again • What if source rejects it too? • Conceptually read-only butunderlying transaction is not Option II: abort the transaction • Should STM be exposed? • Does it prevent non-STM implementations? Option III: use exceptions • Semantics don’t involve STM • Make AbError checked =>don’t ordinarily need log forroll-back if (s.insert(o)) { return false; } else { ??? } throw new AbError(); ? STM.abort(); return false; Aborting atomic blocks throws AbError • What about this code to move an object between collections: boolean move(Collection s, Collection d, Object o) { atomic { if (!s.remove(o)) { return false; } else { if (d.insert(o)) { return true; } else { } } } }
Aborting atomic blocks (ii) • Here still be dragons: void badException() throws AbError { atomic { AbError e = new AbError() { Object payload = new String(“Aborted atomic block“); }; throw e; } } try { badException(); } catch (AbError exn) { … } “Allocated in … • Solution: propagated exception behaves as adeep-copy of the one thrown
External side-effects • Original implementation forbade native methods • Some I/O ‘lucky’ and absorbed by buffers • Want a more general solution – e.g. • Full range of operations potentially available • Controllable semantics, e.g. for debugging or client/server example • Appropriate level for buffering andconflict detection
External side-effects (ii) • General model: • Allow a customized library implementation (or wrapper) to tell ifit’s executed within an atomic block • Allow it to temporarily execute ‘global’ operations, e.g. to perform its own buffering of output associated with the block • Register call-backs to receive notification when the block is committed or aborted • Many similar problems to exception propagation: • Code running outside the block mustn’t see partial updatesmade within the block
o1 o3 o1 o2 Execution within atomic block Execution in specialized library Execution contexts Heap Stack Execution outside atomic block • Execution contexts represent the views that different threads mayhave on the heap at the same time • Invariant: objects and stack frames can only hold references toobjects in ‘more permanent’ contexts
External actions public class ExampleAction { static int x = 0; static VoidExternalAction printX = new VoidExternalAction() { public void action(Context caller_context) { System.out.println (“x=“ + x); }}; static void increment_x() { atomic { x++; printX.doAction(); } printX.doAction(); } }
Combined example void doCombinedUpdate(Connection conn, int new_value, boolean do_commit) throws … { atomic { PreparedStatement pst; pst = conn.prepareStatement (“UPDATE TESTDATA “ “SET field = ? WHERE ID = 1“); pst.setInt(1, newValue); pst.executeUpdate(); shadow = new_value; if (!do_commit) { throw new AbError (“Not committed“); } } }
Future directions • Performance evaluation in a real application • Experiment with ‘external object’ abstraction • Export and bind to in RPC-like style • May make parameter passing mode more intuitive • Avoid problems of writing lots of wrappers • Static analysis for avoiding taking copies • Parameters usually seem to be handed off to callee • Result usually seems to be handed off to caller • Allocate & initialise directly in target context