ICOM 4015 - Advanced Programming

advertisement
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
The header
#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);
}
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
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
Process 0
Process 1
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
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);
}
}
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();
}
}
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
Resource type Get call
Op call
Control call
Semaphore
set
semget
semop
semctl
Message
queue
msgget
msgsnd
msgrcv
msgctl
Shared
memory
region
xxxget
call
shmget
shmat
shmdt
shmctl
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;
Mesg
*mesgptr;
{
int
n;
/* really an msqid from msgget() */
/*
* 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 -
Download