volatile total 0 void add void sub loadaddr R8 total loadaddr R10 total lw R9

Volatile total 0 void add void sub loadaddr r8 total

This preview shows page 22 - 26 out of 168 pages.

volatile total = 0; void add() { void sub() { loadaddr R8 total loadaddr R10 total lw R9 0(R8) lw R11 0(R10) for (i=0; i<N; i++) { for (i=0; i<N; i++) { add R9 1 sub R11 1 } } sw R9 0(R8) sw R11 0(R10) } } Without volatile the compiler could optimize the code. If one thread executes add and another executes sub , what is the value of total when they have finished? CS350 Operating Systems Fall 2013 Synchronization 8 The use of volatile / * What if we DO NOT use volatile * / int -------- volatile total = 0; void add() { void sub() { loadaddr R8 total loadaddr R10 total lw R9 0(R8) lw R11 0(R10) add R9 N sub R11 N sw R9 0(R8) sw R11 0(R10) } } The compiler could aggressively optimize the code., Volatile tells the com- piler that the object may change for reasons which cannot be determined from the local code (e.g., due to interaction with a device or because of an- other thread). CS350 Operating Systems Fall 2013 21
Image of page 22
Synchronization 9 The use of volatile / * Note the use of volatile * / int ________ volatile total = 0; void add() { void sub() { loadaddr R8 total loadaddr R10 total for (i=0; i<N; i++) { for (i=0; i<N; i++) { lw R9 0(R8) lw R11 0(R10) add R9 1 sub R11 1 sw R9 0(R8) sw R11 0(R10) } } } } The volatile declaration forces the compiler to load and store the value on every use. Using volatile is necessary but not sufficient for correct behaviour. Mutual exclusion is also required to ensure a correct ordering of instructions. CS350 Operating Systems Fall 2013 Synchronization 10 Ensuring Correctness with Multiple Threads / * Note the use of volatile * / int volatile total = 0; void add() { void sub() { int i; int i; for (i=0; i<N; i++) { for (i=0; i<N; i++) { Allow one thread to to execute and make others wait total++; total--; Permit one waiting thread to continue execution } } } } Threads must enforce mutual exclusion. CS350 Operating Systems Fall 2013 22
Image of page 23
Synchronization 11 Critical Section Example (Part 1) int list remove front(list * lp) { int num; list element * element; assert(!is empty(lp)); element = lp->first; num = lp->first->item; if (lp->first == lp->last) { lp->first = lp->last = NULL; } else { lp->first = element->next; } lp->num_in_list--; free(element); return num; } The list remove front function is a critical section. It may not work properly if two threads call it at the same time on the same list . (Why?) CS350 Operating Systems Fall 2013 Synchronization 12 Critical Section Example (Part 2) void list append(list * lp, int new item) { list element * element = malloc(sizeof(list element)); element->item = new item assert(!is in list(lp, new item)); if (is empty(lp)) { lp->first = element; lp->last = element; } else { lp->last->next = element; lp->last = element; } lp->num in list++; } The list append function is part of the same critical section as list remove front . It may not work properly if two threads call it at the same time, or if a thread calls it while another has called list remove front CS350 Operating Systems Fall 2013 23
Image of page 24
Synchronization 13 Enforcing Mutual Exclusion mutual exclusion algorithms ensure that only one thread at a time executes the code in a critical section several techniques for enforcing mutual exclusion exploit special hardware-specific machine instructions, e.g., test-and-set , compare-and-swap , or load-link / store-conditional , that are intended for this purpose use mutual exclusion algorithms, e.g.,
Image of page 25
Image of page 26

You've reached the end of your free preview.

Want to read all 168 pages?

  • Left Quote Icon

    Student Picture

  • Left Quote Icon

    Student Picture

  • Left Quote Icon

    Student Picture