1 / 148

Concurrent Programming (part of CSc213/4)

Concurrent Programming (part of CSc213/4). Geoff Coulson Distributed Multimedia Research Group, Department of Computing, Lancaster University geoff@comp.lancs.ac.uk. Administrative details. Geoff Coulson room C2, Computing Building phone 93054 email: geoff@comp.lancs.ac.uk

feivel
Download Presentation

Concurrent Programming (part of CSc213/4)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Concurrent Programming (part of CSc213/4) Geoff Coulson Distributed Multimedia Research Group, Department of Computing, Lancaster University geoff@comp.lancs.ac.uk

  2. Administrative details • Geoff Coulson • room C2, Computing Building • phone 93054 • email: geoff@comp.lancs.ac.uk • web: http://www.comp.lancs.ac.uk/computing/staff/geoff/ • the course • 1 lecture per week for 5 weeks concurrently (sic) with Prof. Hutchison’s Computer Architecture course • then 3 lectures in week 6 • after this, 12 lectures (3 lectures per week) on Operating Systems take us to the end of the term and CSc213/4

  3. Coursework • coursework on web • programming exercises in Java • workflow problem • uses semaphores • public bathroom problem • uses native Java concurrency primitives

  4. Unit 1: Introduction to concurrentprogramming • aims • to define the concept of a process • to distinguish concurrency and parallelism • to introduce concurrent programming • process management • concurrency management • to outline the rest of the course

  5. Three important concepts • processor • the hardware device which executes machine instructions • program • a sequence of instructions awaiting execution • a completely static description of what you would like to happen • process • a program in execution on a processor • an active entity in the system which executes the algorithm defined by a program

  6. Why a process is not a program • a program can be executed by multiple processes at the same time • me running xemacs is a different process from you running xemacs! • one program, two processes • a process can run one program and then another • the pre-processor of a compiler may be a separate program (i.e. executable file) from the syntax analyser, but they may be executed one after the other by the same process

  7. Processes abstract over... • processors • can have many processes regardless of number of processors available • interrupt processing • handling external events like keypresses or clock ticks • context switches • jumps of execution to another part of memory (more detail later) sequential execution processes + interrupts

  8. Concurrency versus parallelism • processes are always concurrent but not always parallel • parallelism means that more than one process is executing at any given instant => more than one processor • concurrency means that more than one process can be underway simultaneously; but maybe that only one is executing at any given instant contextswitches (performedat a timechosen by the scheduler) P1 P2 P1 P2

  9. What is concurrent programming? • writing programs that involve more than one process • examples • implementing operating system internals • exploiting multiprocessor machines to make algorithms run faster • structuring inherently concurrent applications • an X server must listen for keypresses, mouse clicks and draw requests from programs “at the same time” • an animation applet must do the animation, listen for the command to stop, speed up etc. “at the same time” • an aircraft control system must respond to joystick, throttle and wind direction sensors “at the same time”

  10. Event driven programming • programmed either concurrently or sequentially • timeliness/ scheduling issues • structuring issues waitfor(keypress); waitfor(mouse); waitfor(draw_req); waitfor(event); if (event==keypress) ...else if (event==mouse) ......else if (event==draw_req)...

  11. What does concurrent programming involve? • process management • involves single processes • creating, suspending, destroying, ... • concurrency management • involves the coordination/ synchronisation of multiple processes • competition (e.g. for a variable that two processes both want to update) • cooperation (e.g. when one process wants to tell another that a needed result is available)

  12. The need to manage competition 1 • scenario: a bank account object is shared by multiple processes public class Bank_account {private int bal = 0;public void Bank_account(int start_balance) { bal = start_balance;}public void update(int amount) { bal = bal + amount;} } ... Bank_account b = new Bank_account(0);

  13. The need to manage competition 2 • two processes call b.update(5) at around the same time • finalresult may be that balance is 5 rather than 10! process 1: update(5);process 2: update(5); read bal into CPU (0) add 5 to it (5) read bal into CPU (0) write 5 back to bal variable add 5 to it (5) write 5 back to bal

  14. The need to manage cooperation 1 • scenario • process 1 reads a value from the keyboard and places it in a Dimension object • process 2 extracts the value from the Dimension object and draws a box of the given dimensions public class Dimension {private int dim = 0;public void put(int d) { dim = d;}public int get() { return dim;} } Dimension d = new Dimension();

  15. The need to manage cooperation 2 • process 2 runs before process 1 has set d and thus draws a nonsensical box Process 1Process 2 size = Basicio.readInteger(); boxsize = d.get(); d.put(size); box.draw(boxsize);

  16. Outline of rest of course #1 • unit 2: process management • how single processes are managed in Java and UNIX • unit 3: concurrency management: competition 1 • mechanisms and abstractions for mutual exclusion • Java primitives • spin locks • unit 4: concurrency management: competition 2 • mechanisms and abstractions for mutual exclusion • semaphores

  17. Outline of rest of course #2 • unit 5: concurrency management: cooperation 1 • mechanisms and abstractions for condition synchronisation • Java primitives • semaphores (again) • unit 6: concurrency management: cooperation 2 • other concurrency management schemes • unit 7: examples in Java • unit 8: example in UNIX/C

  18. Books • You shouldn’t need to buy one but the following are worth a look: • Lea, D., “Concurrent Programming in Java”, Addison Wesley, 1997, ISBN 0-201-69581-2 • Burns, A., and Davies, G., Concurrent Programming, Addison Wesley, 1993, ISBN 0-201-54417-2 • Switzer, R., "Operating Systems: A Practical Approach", Prentice Hall, 1993, ISBN 0-13-640152-X

  19. Summary • a program is not a process is not a processor • processes abstract over processors, interrupt handling and context switches • concurrency is not the same as parallelism • concurrent programming is programming with more than one process • concurrent programming involves • process management • concurrency management • problem: competition => solution: mutual exclusion • problem: cooperation => solution: condition synchronisation

  20. Unit 2: Process management • aims • to see how processes are managed in Java • processes are called threads in Java • to see how processes are managed in UNIX/C • to compare and contrast the above two notions of process

  21. Java threads • consider a MessagePrinter class with a method print_string() that prints a string in a text window • in a conventional program the main program must wait “a long time” for the output to complete before being able to continue main program message printer

  22. Using a thread • instead, we could use a thread in the MessagePrinter object to allow the main program to continue “immediately” main program message printer concurrency

  23. The “main program” code... /* create a MessagePrinter for the message */ MessagePrinter mp = new MessagePrinter(“Hello sailor”); /* create a new thread for the MessagePrinter */ Thread t = new Thread(mp); /* start the thread */ t.start(); /* ...now do other stuff while the message prints */

  24. Interfaces and “Runnable” (...before we see the MessagePrinter class...) • to create a thread in Java • define a class that implements thejava.lang.Runnable interface • create an object of class Thread • pass an object of the above class to the Thread constructor • n.b. an interface is like a class with method signatures but no method implementations • “implementing” an interface is like extending a class • but, in addition, we must provide implementations of all the method signatures in the specified interface • in Runnable there’s only one signature - public void run()

  25. The MessagePrinter class public class MesssagePrinter implements Runnable {String message;public MessagePrinter(String m) { message = m; }public void run(){ TextArea text = new TextArea(...); text.appendText(message);} }

  26. Summary: the three steps to thread creation 1. Define a class that implements the Runnable interface (i.e. it has “implements Runnable” in the class header and contains a run() method) 2. Pass the above to the constructor of the Thread class 3. Call the start() method of the newly created Thread object -- this causes Java to immediately exececute yourrun() method as a new thread

  27. Some other methods in class Thread • we have seen start() but there are many others... • suspend(), resume() - temporarily pause a thread • stop() - irrevocably stop the thread • sleep() - suspend the thread for a given time • isAlive() - return true iff the thread is started and not yet terminated • join() - suspend calling thread until target completes • Thread.currentThread() - a static class method that allows the calling thread to determine its identifier

  28. Alternative ways to create Java threads • extend the Thread class • implement run() inside the extended class • to create: new EntendedThread().start(); • implement Runnable but hide thread creation inside the new class • constructor of new class contains: new Thread(this).start();

  29. UNIX Processes (n.b. these are not method calls on an object!) • fork() - create ‘child’ process just like the caller • wait() - block until a child process dies • execve() - make calling process run a new program • kill() - send a signal to a process • signal() - set a routine to be called when a signal arrives • pause() - block until a signal arrives • exit() - commit suicide • getpid() - get process identifier of calling process • brk() - set size of caller’s data segment

  30. The fork() call is bizarre... • fork() creates an (almost) identicalcopy (child) of the calling process (parent) • has copies(!!) of the same variables with same values as parent • has same program as parent • just like the parent, the child resumes execution at the line following the fork() call • only difference is the value returned from the fork() call • in the child this is 0 • in the parent this is a value greater than 0 (the actual value returned is the process identifier of the child)

  31. An example /* file: prog.c */ /* file: main.c */ main() main() { { (SIGINT, trap); int pid, status; signal pause (); if ((pid fork ()) < 0) { = exit (0); /* handle error */ } } else if (pid == 0) { execve ("prog","",0); trap() /*NOTREACHED*/ { printf("%d: got it!\n", } else { ()); getpid kill (pid, SIGINT); pid = wait (&status); } } }

  32. init login login login shell shell shell ls cat The UNIX process hierarchy • every process in UNIX (except one) has a parent • processes may create many children (via fork()) • example: the UNIX boot procedure • initially, a single parentless process called init runs • init reads a file which logs the connected terminals • init forks a login process for each terminal • if a login process validates a user it forks a shell process

  33. /* shell */ while(TRUE) { read_command(command, parms); if (fork() == 0) { execve(command, parms, 0); } else { wait(&status); } } The UNIX shell

  34. Comparing Java threads and UNIX processes • Java threads • lightweight (useful for fine grained concurrency) • can share common memory, i.e. common objects (useful for cooperation) • are user level (efficient and system independent) • UNIX processes • heavyweight • cannot share memory (good for isolating activities of separate users) • system level

  35. Summary • to create a thread in Java we create an object of a class that implements the Runnable interface and pass it to the Thread constructor • the Thread class has methods for process management • UNIX processes are created through the fork() call and there are other calls for process management • UNIX processes are very different from Java threads

  36. Unit 3: Concurrency management: competition 1 • aims • to demonstrate how Java controls competition by providing mutual exclusion over critical sections • to begin an exploration of locks which are the foundation on which mutual exclusion is built • to understand some common pitfalls • failed mutual exclusion • deadlock • livelock • unfairness

  37. The Bank_account class revisited public class Bank_account {private int bal = 0;public void update(int a) {bal = bal + a;} } process 1: update(5);process 2: update(5); read bal into CPU (0) add 5 to it (5) read bal into CPU (0) write 5 back to bal variable add 5 to it (5) write 5 back to bal

  38. Towards a solution... • the heart of the problem is that multiple concurrent processes can be executing inside update() simultaneously • we can fix it by only allowing one process at a time to be inside update() • deem update() to be a critical section • implement mutual exclusion over the critical section -- i.e. prevent multiple threads from entering it • do this by meams of a lock • the parable of the bronze statue...

  39. Mutual exclusion and locks multiple processes in Bank_account, theshared resource is the bal instance variable { get_lock() lock provides mutual exclusion critical section shared resource release_lock()

  40. The solution in Java • each object has an (invisible) lock • the lock is obtained via the synchronized statement synchronized(<object for which lock is needed>) {<arbitrary block of code to run with lock held>} • the synchronized statement blocks entry to the code block until the lock can be claimed (cf. get_lock()) • the lock is released after the synchronized statement so another thread can enter (cf. release_lock()) • synchronized can also be applied to a whole method public void synchronized update(int a) { bal = bal + a; }

  41. A safe bank account public class Bank_account {private int bal = 0;public void Bank_account(int start_balance) { bal = start_balance;}public void synchronized update(int amount) { bal = bal + amount;} }

  42. The new Bank_account in action • Java arranges to call get_lock() at start of synchronized method and release_lock() at end process 1: update(5);process 2: update(5); <get_lock() succeeds> read bal into CPU (0) <get_lock() fails> add 5 to it (5) write 5 back to bal variable <release_lock()> <get_lock() succeeds> read bal into CPU (0) add 5 to it (5) write 5 back to bal <release_lock()>

  43. Implementing locks (n.b. Java programmers don’t actually care how locks are implemented!) • there are two main types of lock • spin locks (this unit...) • get_lock()spins until the lock is available; it returns eventually having obtained the lock • spinning means continually executing a while loop that only drops out when the lock has been obtained • blocking locks or semaphores (next unit....) • get_lock()blocks until the lock is available; it returns eventually having obtained the lock • blocking means that the scheduler doesn’t consider the blocked thread for execution until it can be given the lock • Java uses blocking locks but these, in turn, use spin locks (see later...)

  44. A (flawed) spin lock implementation public class Lock { /* pseudo-java */ int lk = 0; public void get_lock() { while(lk == 1) /* do nothing (i.e. spin) */; lk = 1; /* claim the lock */ } public void release_lock() { lk = 0; /* let someone else claim lock */ } } • problem: competition for the lk variable itself! • thread A reads lk as 0 • a context switch occurs before A can claim the lock (i.e. set lk to 1); thread B is scheduled, runs, and claims the lock; • when A is resumed, it carries on and claims the lock as well!

  45. Solutions? • in Java we would fix this by making get_lock() a critical section using synchronize -- but here we are trying to provide locks with which synchronize can be implemented! • three solutions are • disable interrupts • use a special atomic machine instruction • use a software only solution - Peterson’s algorithm

  46. Disabling interrupts • a context switch can only happen when there is an interrupt (see later in OS course) • so, to prevent competition on lk, we disable interrupts while it is being accessed (i.e. we “lock the lock”) public void get_lock() { /* pseudo-java */ try_again: disable_interrupts(); if (lk == 1) { /* lock is taken */ /* permit context switch */reenable_interrupts(); goto try_again; /* spin */ } lk = 1; /* claim lock */reenable_interrupts(); } public void release_lock() { lk = 0;}

  47. Disabling interrupts #2 • an alternative spin lock based on disabling interrupts: public void get_lock() { disable_interrupts();} public void release_lock() { reenable_interrupts(); } • comparative advantage is simplicity + fewer calls of disable_interrupts() and reeneable_ interrupts() • perhaps less overhead • disadvantage is error proneness and the fact that interrupts may be disabled for longer than necessary • clock ticks, IO events etc could be missed

  48. Using a special machine instruction • e.g. test-and-set • int TST(x, val); - in one atomic action, return the old value of variable xand update its value to be val • “atomic action” - an interrupt may come before or after the instruction but not while it is in execution public void get_lock() { /* pseudo-java */ while(TST(lk, 1)) /* spin */; } public void release_lock() { lk = 0;} • other examples are compare-and-swap, fetch-and-add, ...

  49. Peterson’s algorithm • “clever” algorithm; no hardware support needed • two thread version (assumes thread ids of 0 and 1) private int turn = 0; /* new inst. variables */ private bool[] req = {FALSE, FALSE}; public void get_lock() { int pid = Thread.currentThread();int other = 1 - pid; req[pid] = TRUE; turn = other; while(turn == other && req[other]) /* spin */; } public void release_lock() { req[Thread.currentThread()] = FALSE; }

  50. Pitfalls in concurrent programming • the following are the most common pitfalls • failed mutual exclusion • deadlock • livelock • unfairness • we will understand these by examining a series of flawed but plausible approximations to Peterson’s algorithm... • in the process we will better understand how Peterson’s algorithm works

More Related