Presentation is loading. Please wait.

Presentation is loading. Please wait.

Announcements. Cooperating Processes  Operating systems allow for the creation and concurrent execution of multiple processes & threads  eases program.

Similar presentations


Presentation on theme: "Announcements. Cooperating Processes  Operating systems allow for the creation and concurrent execution of multiple processes & threads  eases program."— Presentation transcript:

1 Announcements

2 Cooperating Processes  Operating systems allow for the creation and concurrent execution of multiple processes & threads  eases program complexity  increases efficiency  Can they work together? How?  Messages?  What about shared memory?  Operating systems allow for the creation and concurrent execution of multiple processes & threads  eases program complexity  increases efficiency  Can they work together? How?  Messages?  What about shared memory?

3 Problems with concurrent execution  Concurrent processes (or threads) often need to share data (maintained either in shared memory or files) and resources  If there is no controlled access to shared data, some processes will obtain an inconsistent view of this data  The action performed by concurrent processes will then depend on the order in which their execution is interleaved  Consider two threads one doing x++ and the other doing x--. How many different values for x?  Concurrent processes (or threads) often need to share data (maintained either in shared memory or files) and resources  If there is no controlled access to shared data, some processes will obtain an inconsistent view of this data  The action performed by concurrent processes will then depend on the order in which their execution is interleaved  Consider two threads one doing x++ and the other doing x--. How many different values for x?

4 The Critical-Section Problem  Consider a system:  n processes {P 0, P 1, …, P n-1 }  Each process has a critical section  changing common values  updating tables  etc.  Access to those variables must be safe  mutually exclusive  Consider a system:  n processes {P 0, P 1, …, P n-1 }  Each process has a critical section  changing common values  updating tables  etc.  Access to those variables must be safe  mutually exclusive

5 The Critical-Section Problem  A solution must satisfy 3 conditions:  Mutual exclusion  Progress  Bounded waiting  No assumptions can be made about speed  Solutions execute some entry code and some exit code surrounding critical section.  A solution must satisfy 3 conditions:  Mutual exclusion  Progress  Bounded waiting  No assumptions can be made about speed  Solutions execute some entry code and some exit code surrounding critical section.

6 Critical Section Properties  Mutual Exclusion  At any time, at most one process can be in its critical section (CS)  Progress  Only processes that are not executing in their CS can participate in the decision of who will enter next in the CS.  This selection cannot be postponed indefinitely  Mutual Exclusion  At any time, at most one process can be in its critical section (CS)  Progress  Only processes that are not executing in their CS can participate in the decision of who will enter next in the CS.  This selection cannot be postponed indefinitely

7 Critical Section Properties  Bounded Waiting  After a process has made a request to enter it’s CS, there is a bound on the number of times that the other processes are allowed to enter their CS  otherwise the process will suffer from starvation  Of course there must also be no deadlock  Bounded Waiting  After a process has made a request to enter it’s CS, there is a bound on the number of times that the other processes are allowed to enter their CS  otherwise the process will suffer from starvation  Of course there must also be no deadlock

8 pthread_mutex  int pthread_mutex_init( pthread_mutex_t *mutex_lock, const pthread_mutexattr_t *lock_attr);  int pthread_mutex_lock( pthread_mutex_t *mutex_lock);  int pthread_mutex_unlock( pthread_mutex_t *mutex_lock);  int pthread_mutex_trylock( pthread_mutex_t *mutex_lock);  int pthread_mutex_init( pthread_mutex_t *mutex_lock, const pthread_mutexattr_t *lock_attr);  int pthread_mutex_lock( pthread_mutex_t *mutex_lock);  int pthread_mutex_unlock( pthread_mutex_t *mutex_lock);  int pthread_mutex_trylock( pthread_mutex_t *mutex_lock);

9 #include void *find_min(void *list_ptr) pthread_mutex_t minimum_value_lock; int minimum_value, partial_list_size; main(){ minimum_value = MIN_INT; pthread_init(); pthread_mutex_init(&minimum_value_lock, NULL); /*inititalize lists etc, create and join threads*/ } void *find_min(void *list_ptr){ int *partial_list_ptr, my_min = MIN_INT, i; partial_list_ptr = (int *)list_ptr; for (i = 0; i < partial_list_size; i++) if (partial_list_ptr[i] < my_min) my_min = partial_list_ptr[i]; pthread_mutex_lock(minimum_value_lock); if (my_min < minimum_value) minimum_value = my_min; pthread_mutex_unlock(minimum_value_lock); pthread_exit(0); }

10 Locking Overhead  Serialization points  Minimize the size of critical sections  Be careful  Rather than wait, check if lock is available  pthread_mutex_trylock  If already locked, will return EBUSY  Will require restructuring of code  Serialization points  Minimize the size of critical sections  Be careful  Rather than wait, check if lock is available  pthread_mutex_trylock  If already locked, will return EBUSY  Will require restructuring of code

11 pthread_mutex_trylock /* Finding k matches in a list */ void *find_entries(void *start_pointer) { /* This is the thread function */ struct database_record *next_record; int count; current_pointer = start_pointer; do { next_record = find_next_entry(current_pointer); count = output_record(next_record); } while (count < requested_number_of_records); } int output_record(struct database_record *record_ptr) { int count; pthread_mutex_lock(&output_count_lock); output_count ++; count = output_count; pthread_mutex_unlock(&output_count_lock); if (count <= requested_number_of_records) print_record(record_ptr); return (count); }

12 pthread_mutex_trylock /* rewritten output_record function */ int output_record(struct database_record *record_ptr) { int count; int lock_status; lock_status=pthread_mutex_trylock(&output_count_lock); if (lock_status == EBUSY) { insert_into_local_list(record_ptr); return(0); } else { count = output_count; output_count += number_on_local_list + 1; pthread_mutex_unlock(&output_count_lock); print_records(record_ptr, local_list, requested_number_of_records - count); return(count + number_on_local_list + 1); }

13 Cooperation through shared mem. x P0P1 1. Wait until x has a value 2. Use the value 3. Change the value to indicate used 1. Wait until x is able to be set 2. Produce a value 3. Set x to the value Can we increase the parallelism? What problems does this entail? x1 x2 x3 … xn

14 The Producer-Consumer Problem repeat … produce an item in nextp … while counter == n do no-op buffer[in] = nextp in = (in + 1) mod n counter = counter + 1 until false repeat … while counter == 0 do no-op nextc = buffer[out] out = (out + 1) mod n counter = counter -1 … consume the item in nextc … until false Are these correct? Always?

15 Semaphores  Synchronization tool provided by the OS  Integer variable that gives us two operations  wait(s) while s <= 0 do nothing s = s - 1  signal(s) s = s + 1  Modifications to s are atomic.  Synchronization tool provided by the OS  Integer variable that gives us two operations  wait(s) while s <= 0 do nothing s = s - 1  signal(s) s = s + 1  Modifications to s are atomic.

16 repeat wait(mysem) critical section signal(mysem) remainder section until false Shared semaphore: mysem= 1; Will this work for n processes? Semaphores for Critical Sections

17 Semaphore Implementation  How do we wait?  spin?  sleep? – How long? How do we wake up?  Solution:  Let process block itself by placing in waiting queue  wait call places the process on the queue  When a process is blocked, it must be woken up  signal process must wake up next process on queue  Semaphore  struct semaphore { int value; Queueprocesses; };  How do we wait?  spin?  sleep? – How long? How do we wake up?  Solution:  Let process block itself by placing in waiting queue  wait call places the process on the queue  When a process is blocked, it must be woken up  signal process must wake up next process on queue  Semaphore  struct semaphore { int value; Queueprocesses; };

18 Wait wait(Semaphore s) { s.value = s.value - 1; if (s.value < 0) { add this process to s.L block; } wait(Semaphore s) { s.value = s.value - 1; if (s.value < 0) { add this process to s.L block; }

19 signal(Semaphore s) { s.value = s.value + 1; if (s.value <= 0) { remove a process P from s.L wakeup(P); } signal(Semaphore s) { s.value = s.value + 1; if (s.value <= 0) { remove a process P from s.L wakeup(P); } Signal

20 Details  Critical  Semaphore operations must be atomic  Uniprocessor  simply inhibit interrupts (normal user can’t)  Use TestAndSet instruction  Multiprocessor  hardware must provide special support or  use software solutions  Critical  Semaphore operations must be atomic  Uniprocessor  simply inhibit interrupts (normal user can’t)  Use TestAndSet instruction  Multiprocessor  hardware must provide special support or  use software solutions

21 Using semaphores  Two processes P1 and P2  Statements S1 and S2  S2 must execute only after S1  Two processes P1 and P2  Statements S1 and S2  S2 must execute only after S1 P1: S1; signal(synch); P2: wait(synch); S2;

22 Consider P0: wait(S); wait(Q);. signal(S); signal(Q); P1: wait(Q); wait(S);. signal(Q); signal(S); Is there anything wrong with this?

23 Semaphores  Semaphores can be:  binary  counting  Binary  integer variable is 0 or 1  strictly a mutual exclusion variable  pthread_mutex  Counting  integer variable indicates quantity  allows more than one process/thread in at a time  Semaphores can be:  binary  counting  Binary  integer variable is 0 or 1  strictly a mutual exclusion variable  pthread_mutex  Counting  integer variable indicates quantity  allows more than one process/thread in at a time

24 Bounded Buffer Problem P0P1 x1 x2 x3 … xn

25 Bounded Buffer Solution repeat produce an item in nextp wait(empty); wait(mutex); add nextp to the buffer signal(mutex); signal(full); until false repeat produce an item in nextp wait(empty); wait(mutex); add nextp to the buffer signal(mutex); signal(full); until false repeat wait(full); wait(mutex); remove an item from buffer place it in nextc signal(mutex); signal(empty); consume the item in nextc until false repeat wait(full); wait(mutex); remove an item from buffer place it in nextc signal(mutex); signal(empty); consume the item in nextc until false Shared semaphore: empty = n, full = 0, mutex = 1;

26 Posix Semaphores  Counting semaphores  sem_init - creates a unnamed semaphore and initializes it  int sem_init(sem_t *sem, int pshared, unsigned int value);  sem_open - creates a named semaphore and initializes it  sem_t *sem_open(const char *name, int oflag,  mode_t mode, unsigned int value);  sem_wait - performs a wait operation  int sem_wait(sem_t *sem);  int sem_trywait(sem_t *sem);  int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);  sem_post - performs a signal operation  int sem_post(sem_t *sem);  Counting semaphores  sem_init - creates a unnamed semaphore and initializes it  int sem_init(sem_t *sem, int pshared, unsigned int value);  sem_open - creates a named semaphore and initializes it  sem_t *sem_open(const char *name, int oflag,  mode_t mode, unsigned int value);  sem_wait - performs a wait operation  int sem_wait(sem_t *sem);  int sem_trywait(sem_t *sem);  int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);  sem_post - performs a signal operation  int sem_post(sem_t *sem);

27 #include void *functionC(void *ptr); int counter = 0; sem_t sem; main() { int rc1, rc2; pthread_t thread1, thread2; sem_init(&sem, PTHREAD_PROCESS_PRIVATE, 1); // Now it is set to one, one person will be able to access at a time printf("Got semaphore %d\n",sem); /* Create independent threads each of which will execute functionC */ if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) ) { printf("Thread creation failed: %d\n", rc1); } if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) ) { printf("Thread creation failed: %d\n", rc2); } /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */ pthread_join( thread1, NULL); pthread_join( thread2, NULL); sem_close(&sem); exit(0); } void *functionC(void *ptr) { int tmp; sem_wait(&sem); tmp = counter; sleep(1); tmp++; counter = tmp; printf("Counter value: %d\n",counter); sem_post(&sem); } ~ This works for Linux

28 #ifdef __APPLE__ #include #else #include #endif void qsem_create(void * semStructure, int initialValue) { #ifdef __APPLE__ semaphore_create(mach_task_self(), (semaphore_t *)semStructure, SYNC_POLICY_FIFO, initialValue); #else int pshared = 0; sem_init((sem_t *)semStructure, pshared, initialValue); #endif } void qsem_signal(void * semStructure) { #ifdef __APPLE__ semaphore_signal(*((semaphore_t *)semStructure)); #else sem_post((sem_t *)semStructure); #endif } void qsem_wait(void * semStructure) { #ifdef __APPLE__ semaphore_wait(*((semaphore_t *)semStructure)); #else sem_wait((sem_t *)semStructure); #endif } void qsem_close(void * semStructure) { #ifdef __APPLE__ semaphore_destroy(mach_task_self(), *((semaphore_t *)semStructure)); #else sem_close((sem_t *)semStructure); #endif } #ifdef __APPLE__ semaphore_t sem; #else sem_t sem; #endif

29 Unix System V Semaphores  Are a generalization of the counting semaphores (more operations are permitted).  A semaphore includes:  the current value S of the semaphore  number of processes waiting for S to increase  number of processes waiting for S to be 0  System calls  semget creates an array of semaphores  semctl allows for the initialization of semaphores  semop performs a list of operations: one on each semaphore (atomically)  Are a generalization of the counting semaphores (more operations are permitted).  A semaphore includes:  the current value S of the semaphore  number of processes waiting for S to increase  number of processes waiting for S to be 0  System calls  semget creates an array of semaphores  semctl allows for the initialization of semaphores  semop performs a list of operations: one on each semaphore (atomically)

30 Unix Semaphore Code  Creation  union semun argument;  key_t key = IPC_PRIVATE;  int flags = 0777 | IPC_CREAT;  int semid = semget(key, 1, flags);  argument.val = initialvalue;  semctl(semid, 0, SETVAL, argument);  Destruction  int ignored_int;  union semun ignored;  semctl(semid, ignored_int, IPC_RMID, ignored);  Creation  union semun argument;  key_t key = IPC_PRIVATE;  int flags = 0777 | IPC_CREAT;  int semid = semget(key, 1, flags);  argument.val = initialvalue;  semctl(semid, 0, SETVAL, argument);  Destruction  int ignored_int;  union semun ignored;  semctl(semid, ignored_int, IPC_RMID, ignored); #include void *functionC(void *ptr); int counter = 0; int sem; #define NSEMS 1 #define SEMFLAG (IPC_CREAT| 0666) union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ };

31 Unix Semaphores  Each operation to be done is specified by a value sem_op.  Let S be the semaphore value  if sem_op > 0: (signal operation)  S is incremented and process awaiting for S to increase are awaken  if sem_op = 0:  If S=0: do nothing  if S!=0, block the current process on the event that S=0  if sem_op < 0: (wait operation)  if S >= | sem_op | then S = S - | sem_op | then if S <=0 wait  Each operation to be done is specified by a value sem_op.  Let S be the semaphore value  if sem_op > 0: (signal operation)  S is incremented and process awaiting for S to increase are awaken  if sem_op = 0:  If S=0: do nothing  if S!=0, block the current process on the event that S=0  if sem_op < 0: (wait operation)  if S >= | sem_op | then S = S - | sem_op | then if S <=0 wait

32 Wait and Signal  Set up the operations array for 1 semaphore  struct sembuf operations[1];  operations[0].sem_num = 0;  operations[0].sem_flg = SEM_UNDO;  Wait  operations[0].sem_op = -1;  Signal  operations[0].sem_op = 1;  Execute the operation on 1 semaphore  semop(semid, operations, 1);  Set up the operations array for 1 semaphore  struct sembuf operations[1];  operations[0].sem_num = 0;  operations[0].sem_flg = SEM_UNDO;  Wait  operations[0].sem_op = -1;  Signal  operations[0].sem_op = 1;  Execute the operation on 1 semaphore  semop(semid, operations, 1);

33 Semaphores & Interrupts  Semaphore operations may be interrupted  Will not be restarted  Semop will return -1  Semaphore operations may be interrupted  Will not be restarted  Semop will return -1 int sem_wait(int semid) { struct sembuf operations[1]; int retval; operations[0].sem_num = 0; operations[0].sem_op = -1; operations[0].sem_flg = SEM_UNDO; while ((retval = semop(semid, operations, 1)) == -1) { if (errno != EINTR) { fprintf(stderr,"sem_wait error %d\n", errno); exit(4); } return retval; }

34 Unix Semaphores  Operating System level data structure  Can be shared among processes  Identified by a key and an ID  List semaphores  $ ipcs  Remove zombie semaphores  $ ipcrm -s semid  Operating System level data structure  Can be shared among processes  Identified by a key and an ID  List semaphores  $ ipcs  Remove zombie semaphores  $ ipcrm -s semid

35 Classical Synchronization Problems  Counting semaphores from binary semaphores  Bounded Buffer  Shared buffer between producer and consumer  Readers and Writers  data object shared between many  some read only  some write only  Dining Philosophers  n processes  p resources  Counting semaphores from binary semaphores  Bounded Buffer  Shared buffer between producer and consumer  Readers and Writers  data object shared between many  some read only  some write only  Dining Philosophers  n processes  p resources

36 Binary to Counting Semaphores  Can you create a counting semaphore from binary semaphores?  Needed:  Integer count  Operations on the count must be atomic  Must block processes appropriately  How many binary semaphores are needed?  Can you do it with just one?  Can you create a counting semaphore from binary semaphores?  Needed:  Integer count  Operations on the count must be atomic  Must block processes appropriately  How many binary semaphores are needed?  Can you do it with just one?

37 Binary to Counting Semaphores Typedef struct qsem { pthread_mutex_t s; int value; } void wait(qsem_t* q) { pthread_mutex_lock(q->s); q->value--; if (value < 0) { // I need to block..... how? } pthread_mutex_unlock(q->s); } void signal(qsem_t* q) { pthread_mutex_lock(q->s); q->value++; if (value <= 0) { // I need to wake someone //..... how? } pthread_mutex_unlock(q->s); }

38 Binary to Counting Semaphores typedef struct qsem { pthread_mutex_t s1; pthread_mutex_t s2; int value; } void wait(qsem_t* q) { pthread_mutex_lock(&(q->s1)); q->value--; if (value < 0) { pthread_mutex_unlock(&(q->s1)); pthread_mutex_lock(&(q->s2)); } pthread_mutex_unlock(&(q->s1)); } void qsem_create(qsem_t *q, int initialvalue) { pthread_mutex_init(&(q->s1), NULL); pthread_mutex_init(&(q->s2), NULL); // We must initialize s1 to 1(default) // and s2 to 0 (we must lock it) pthread_mutex_lock(&(q->s2)); q->value = initialvalue; } void signal(qsem_t* q) { pthread_mutex_lock(&(q->s1)); q->value++; if (value <= 0) pthread_mutex_unlock(&(q->s2)); else pthread_mutex_unlock(&(q->s1)); }

39 Bounded Buffer Problem P0P1 x1 x2 x3 … xn

40 Bounded Buffer Solution? repeat … produce an item in nextp … while counter == n do no-op buffer[in] = nextp in = (in + 1) mod n counter = counter + 1 until false repeat … while counter == 0 do no-op nextc = buffer[out] out = (out + 1) mod n counter = counter -1 … consume the item in nextc … until false

41 Bounded Buffer Solution repeat produce an item in nextp wait(empty); wait(producer_mutex); add nextp to the buffer only modify in signal(producer_mutex); signal(full); until false repeat wait(full); wait(consumer_mutex); remove an item from buffer place it in nextc only modify out signal(consumer_mutex); signal(empty); consume the item in nextc until false Shared semaphore: empty = n, full = 0, producer_mutex = 1, consumer_mutex = 1; Note: We don’t need counter any more. Why?

42 The Dining Philosophers Problem  5 philosophers who only eat and think  each need to use 2 forks for eating  we have only 5 forks  Illustrates the difficulty of allocating resources among processes/threads without deadlock and starvation  5 philosophers who only eat and think  each need to use 2 forks for eating  we have only 5 forks  Illustrates the difficulty of allocating resources among processes/threads without deadlock and starvation

43 The Dining Philosophers Problem  Each philosopher is a process  One semaphore per fork:  fork: array[0..4] of semaphores  Initialization: fork[i].count:=1 for i:=0..4  A first attempt:  Each philosopher is a process  One semaphore per fork:  fork: array[0..4] of semaphores  Initialization: fork[i].count:=1 for i:=0..4  A first attempt: Process Pi: repeat think; wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); forever Deadlock if each philosopher starts by picking left fork!

44 The Dining Philosophers Problem  A solution: admit only 4 philosophers at a time that tries to eat  Then 1 philosopher can always eat when the other 3 are holding 1 fork  Introduce semaphore T that limits at 4 the numb. of philosophers “sitting at the table”  Initialize: T.count:=4  A solution: admit only 4 philosophers at a time that tries to eat  Then 1 philosopher can always eat when the other 3 are holding 1 fork  Introduce semaphore T that limits at 4 the numb. of philosophers “sitting at the table”  Initialize: T.count:=4 Process Pi: repeat think; wait(T); wait(fork[i]); wait(fork[i+1 mod 5]); eat; signal(fork[i+1 mod 5]); signal(fork[i]); signal(T); forever

45 Other solutions  A philosopher may only pick up forks in pairs  must allocate all resources at once  Asymmetric solution  odd philosophers select left then right  even philosophers select right then left  All solutions must not starve a philosopher  A philosopher may only pick up forks in pairs  must allocate all resources at once  Asymmetric solution  odd philosophers select left then right  even philosophers select right then left  All solutions must not starve a philosopher

46 Readers and Writers Problem  Data object is shared  many readers  many writers  Many can read at the same time  Only one writer at a time  no reading while writing  Many different varieties  reader priority  writer priority  Data object is shared  many readers  many writers  Many can read at the same time  Only one writer at a time  no reading while writing  Many different varieties  reader priority  writer priority

47 Readers - Writers (priority?) Shared Semaphore mutex=1, wrt = 1; Shared integerreadcount = 0; Shared Semaphore mutex=1, wrt = 1; Shared integerreadcount = 0; wait(wrt); write to the data object signal(wrt); wait(wrt); write to the data object signal(wrt); wait(mutex); readcount = readcount + 1; if (readcount == 1) wait(wrt); signal(mutex); read the data wait(mutex); readcount = readcount - 1; if (readcount == 0) signal(wrt); signal(mutex); wait(mutex); readcount = readcount + 1; if (readcount == 1) wait(wrt); signal(mutex); read the data wait(mutex); readcount = readcount - 1; if (readcount == 0) signal(wrt); signal(mutex);

48 Readers – Writers (priority?) wait (outerQ) wait (rsem) wait (rmutex) readcnt++ if (readcnt == 1) wait (wsem) signal(rmutex) signal (rsem) signal (outerQ) READ wait (rmutex) readcnt--; if (readcnt == 0) signal (wsem) signal (rmutex) wait (outerQ) wait (rsem) wait (rmutex) readcnt++ if (readcnt == 1) wait (wsem) signal(rmutex) signal (rsem) signal (outerQ) READ wait (rmutex) readcnt--; if (readcnt == 0) signal (wsem) signal (rmutex) wait (wsem) writecnt++; if (writecnt == 1) wait (rsem) signal (wsem) wait (wmutex) WRITE signal (wmutex) wait (wsem) writecnt--; if (writecnt == 0) signal (rsem) signal (wsem) wait (wsem) writecnt++; if (writecnt == 1) wait (rsem) signal (wsem) wait (wmutex) WRITE signal (wmutex) wait (wsem) writecnt--; if (writecnt == 0) signal (rsem) signal (wsem) outerQ, rsem, rmutex, wmutex, wsem: = 1

49 The Barbershop Entrance Standing room area Sofa Barber chairs Cashier Exit


Download ppt "Announcements. Cooperating Processes  Operating systems allow for the creation and concurrent execution of multiple processes & threads  eases program."

Similar presentations


Ads by Google