240 likes | 400 Views
Semaphores and typical applications. What are semaphores and messages How to control a critical section with semaphores Typical process coordination problems. Semaphore code from Stevens (QEPD). #include <sys/types.h> // The header file info #include <sys/ipc.h> #include <sys/sem.h>
E N D
Semaphores and typical applications What are semaphores and messages How to control a critical section with semaphores Typical process coordination problems
Semaphore code from Stevens (QEPD) • #include <sys/types.h> // The header file info • #include <sys/ipc.h> • #include <sys/sem.h> • #define KEY ((key_t) 54321) // an unlikely key • #define COUNT 20000 • struct sembuf op_up[1] = { 0, 1, 0 }; // A useful trick for semops • struct sembuf op_down[1] = { 0, -1, 0 }; // use -1 for down – use this in wrappers • main() { • register int i, semid; // Always protect system code • if ( (semid = semget(KEY, 1, 0666 | IPC_CREAT)) < 0) err_sys("semget error"); • for (i = 0; i < COUNT; i++) { • if (semop(semid, &op_up[0], 1) < 0) err_sys("semop up error"); • if (semop(semid, &op_down[0], 1) < 0) err_sys("semop down error"); • } • if (semctl(semid, 0, IPC_RMID, (struct semid_ds *) 0) < 0) err_sys("IPC_RMID error"); • exit(0); • } The header
Concurrency - From last time • The theoretical core of OS • An OS creates a set of processes that run concurrently • A process is like a person - it has • a stream of consciousness • possessions - memory, files, data • is created, reproduces, dies • interacts with other processes • In actuality, it is a program in execution • Concurrent process misbehaviors • Race conditions - unpredictable results because processes simultaneously modify data or devices • Deadlocks - Each has what the other wants • Starvation - some processes go hungry - others eat well
Some operating system ideas - also review • Everything is a file - even devices • This allows a program to work with human input, or a device, or a temporary or permanent file • Interrupt-driven behavior • Example - windows - process is simultaneously sensitive to events from mouse, keyboard, process subsystem, and window manager • Caching - Foreground and background copies • Used in • Cache memory • Swapping • The disk block cache - recent transactions are in memory • Networking utilities
Processes and their states • The process state includes the following • Running/ready/blocked (waiting on an event/events) • Priority • Kernel/User mode • In-memory/swapped • Process ID • Priority • The process owns • U-area (but user can’t examine/modify it) • Entries in the system open-file table • Its own file control blocks (linked to the system table) • Its own memory space
The system process table • Used for scheduling and control of processes • Scheduler acts on timer interrupt or a process state change • It schedules the highest-priority process that is ready • It causes a context switch (gives the process control) • This mechanism • Gives system and I/O processes high priority • Keeps the CPU puercos from monopolizing • Interrupts are outside process country • This avoids make a context switch for each interrupt • It means the interrupt service routines use only the kernels memory
Mutual Exclusion - software solutions • Unsuccessful solutions (on separate slides) • Strict alternation • Algorithms where mutual exclusion fails • Peterson’s algorithm • Description of Bakery Algorithm • Just like Baskin-Robbins - incoming process takes a number • Since two users can grab same number, lowest-number process gets priority
Avoiding busy waiting - Semaphores and messages • Classical semaphores • The semaphore is an ADT with a counter, a process queue, and two operations • The down operation sleeps enqueued if the counter is zero, and then decrements the counter • The up operation increments the counter and awakens a sleeper if the counter was 0. • The down operation enters a critical section, the up leaves it. • Messages • Reliable messages to an administrator work like a down or up • Messages and semaphores are equivalent • That’s why
Process 0 Process 1 Semaphores and messages - continued • Mistakes are easy • Deadlock • Gateway-controlling and resource-controlling semaphores invoked in wrong order - deadlocks and slow performance • Example of a deadlock creator //process 0 Wait(a) Wait(b) //critical section Signal(a) Signal(b) //process 1 Wait(b) Wait(a) //critical section Signal(b) Signal(a) a b If process 1 is like process 0 (semaphores a and b requested In same order, this deadlock can’t occur
Producer-consumer problem again • Definition • Producers • They produce items and place in a buffer as long as one is available. • They wait (and stop producing) when no buffer is available • Consumers • They wait until a buffer contains an item and then take it • They then consume the item • What needs protection • The buffer place and take operations, not the producing or consuming • Possible deadlock • Producer is waiting for a consumer to take, but consumer can’t take because producer has buffering operation locked • This problem can’t be solved with only one semaphore
Producer-consumer with general semaphores • Global variables • Item buffers[Nbuffers]; • Int last_filled=N_buffers, oldest_item=0, number_filled=0; • // underrated programming technique, give descriptive and nonambiguous names, not i, j, in, out • Semaphores • Buffer_available=n,items_available=0;pool_available=1; • Technique • Circular buffering step operation • Next = (next+1)%N_buffers // steps pointer from end to start
The code itself • consumer() { • While(1) { • Wait (items_available); • Wait (pool_available); • Old_item=Buffers[oldest_item]; • Count--;step(oldest_item) • Signal(buffer_available); • Signal(pool_available); • New_item=produce(); • } • } • Producer() { • While(1) { • New_item=produce(); • Wait (buffer_available); • Wait (pool_available); • Buffers[next_available]=new_item; • Count++;step(last_filled) • Signal(items_available); • Signal(pool_available); • } • }
Language Mechanisms - Monitors • Monitor is a class with mutual exclusion: it has • Member functions • Data members • Condition variables (user processes wait on these) • Two ways to enter • Normal • Returning from wait on a condition variable • Two ways to leave • Normal (return from a member function) • Waiting on a condition variable • Monitors can be implemented by: • Preprocessor that generates semaphore code • Compiler modification
Classical IPC problems • Producer-consumer • Scenario • Producer produces information • Consumer consumes it • Both must wait on buffer availability • Problem resembler disk I/O and print servers • Code is in book - both C and monitor • Readers-Writers • Scenario • Readers can write whenever no writer is active • Writers must have solitude • Problem resembles database • Code in book - both C and monitor • Dining Philosophers • Scenario • N philosophers think, wait for chopsticks, and eat • Problem is useless but illustrative • Code - both C and monitor
System V IPC • xxxget call • int xxxget(key, type-dependent, flags) • returns • Positive number, which is the instance ID • For error • xxxop call • The basic operation • Works on regions, groups of semops, or message queues • xxxctl call • Does specialized operations – removes instance, sets values and permissions
Stevens – semaphore get #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define KEY ((key_t) 98765L) #define PERMS 0666 main() { int i, semid; for (i = 0 ; i < 1000; i++) { if ( (semid = semget(KEY, 1, PERMS | IPC_CREAT)) < 0) err_sys("can't create semaphore"); printf("semid = %d\n", semid); if (semctl(semid, 0, IPC_RMID, (struct semid_ds *) 0) < 0) err_sys("can't remove semaphore"); } }
#include "msgq.h" main() { int readid, writeid; /* * Open the message queues. The server must have * already created them. */ if ( (writeid = msgget(MKEY1, 0)) < 0) err_sys("client: can't msgget message queue 1"); if ( (readid = msgget(MKEY2, 0)) < 0) err_sys("client: can't msgget message queue 2"); client(readid, writeid); /* * Now we can delete the message queues. */ if (msgctl(readid, IPC_RMID, (struct msqid_ds *) 0) < 0) err_sys("client: can't RMID message queue 1"); if (msgctl(writeid, IPC_RMID, (struct msqid_ds *) 0) < 0) err_sys("client: can't RMID message queue 2"); exit(0); }
Wrapper function for msgsnd mesg_send(id, mesgptr) int id; /* really an msqid from msgget() */ Mesg *mesgptr; { /* * Send the message - the type followed by the optional data. */ if (msgsnd(id, (char *) &(mesgptr->mesg_type), mesgptr->mesg_len, 0) != 0) err_sys("msgsnd error"); } /* * Receive a message from a System V message queue. * The caller must fill in the mesg_type field with the desired type. * Return the number of bytes in the data portion of the message. * A 0-length data message implies end-of-file. */
Wrapper for msgrcv int mesg_recv(id, mesgptr) int id; /* really an msqid from msgget() */ Mesg *mesgptr; { int n; /* * Read the first message on the queue of the specified type. */ n = msgrcv(id, (char *) &(mesgptr->mesg_type), MAXMESGDATA, mesgptr->mesg_type, 0); if ( (mesgptr->mesg_len = n) < 0) err_dump("msgrcv error"); return(n); /* n will be 0 at end of file */ }
Header for both wrapper functions /* * Definition of "our" message. * * You may have to change the 4096 to a smaller value, if message queues * on your system were configured with "msgmax" less than 4096. */ #define MAXMESGDATA (4096-16) /* we don't want sizeof(Mesg) > 4096 */ #define MESGHDRSIZE (sizeof(Mesg) - MAXMESGDATA) /* length of mesg_len and mesg_type */ typedef struct { int mesg_len; /* #bytes in mesg_data, can be 0 or > 0 */ long mesg_type; /* message type, must be > 0 */ char mesg_data[MAXMESGDATA]; } Mesg;
General pattern for an IPC example • Main program • Create the IPC (xxxget) • Initialize the IPC (xxxctl) • Set up the cleanup() function • Create children to be the actors using a loop containing fork() • Does monitoring function or creates a monitor • note: Global variables are usually needed • Child actors • Can be persistent (barbers, philosophers) • Can be temporary (readers, customers, Loreina says writers are immortal) • Either live forever (with while loop) if immortal • Or exit(0) if mortal
Some specifics • Definition • Decide what IPC is needed and give valid names • Decide what other global variables are needed and what protection is needed • Write pseudocode, then fill in to readable code • Program operation • Examples can be done as real-time (uses sleep()) or discrete-time simulation • DTS is faster, gives better statistics, but takes some thought • Terminal output can be a problem – output from child needs a flush, especially if control characters are involved • Think about the statistics, there is usually a dimensionless utilization parameter or ratio • Example of this is ratio of haircutting capacity to offered business in the barbershop
Example of a cleanup() function • void cleanup() { • if (0>(msgctl(semid, IPC_RMID, (struct msqid_ds *) 0) ) error_exit(“couldn’t remove • Message queue”); • exit(0); • } • /* code segment to set up signals for cleanup • extern void cleanup; • ………… • for (int signal=0;signal<32;signal++) signal(signal,cleanup); • Comments: • Cleanup must be declared extern or the signal mechanism won’t find it • This won’t work for all signals, notably 9 • Response to 9 (SIGKILL) isn’t alterable because it is important to be able to really control the system
Methodology for the sleepy barber • Semaphores • awaitingBarber – • awaitingCustomer – • mutex – controls waiting-room variables, used whenever a customer arrives or a haircut starts • Global variables • emptyChairs -