Title: Tuesday, June 27, 2006
1Tuesday, June 27, 2006
- "If the 8086 architects had designed a car, they
would have produced one with legs, to be
compatible with the horse." - - Anonymous
2Dining Philosophers Example
monitor dp enum thinking, hungry, eating
state5 condition self5 void pickup(int
i) void putdown(int i) void test(int i)
void init() for (int i 0 i lt 5
i) statei thinking
3Dining Philosophers
void pickup(int i) statei
hungry testi if (statei !
eating) selfi.wait() void putdown(int
i) statei thinking // test left and
right neighbors test((i4) 5) test((i1)
5)
4Dining Philosophers
void test(int i) if ( (state(I 4) 5 !
eating) (statei hungry)
(state(i 1) 5 ! eating)) statei
eating selfi.signal()
5Monitors
6- Low level atomic operations
- interrupt disable
- TestSet
- CompareSwap
- High level atomic operations
- mutex
- semaphores
- monitors
7- Three primary mechanisms used for IPC in POSIX
- Message queues
- Semaphores
- Shared memory
8- Derived from Unix System V
- These three resource types are global and handled
by the system. - Access permissions
- May outlive the process that created it.
- Programmer must take care of freeing these
resources.
9shmget system call
- shm_idshmget(200, 2048, IPC_CREAT 0600)
- Allocate a shared memory segment of 2048 bytes
accessible only to current user.
10- 0400 user may read from this resource
- 0200 user may write to this resource
- 0040?
- 0002?
11ftok() system call - generate an IPC key
- key_t ftok(const char path, int id)
- The ftok() function returns a key based on path
and id The path argument must be the pathname
of an existing file. -
12ftok() system call - generate an IPC key
- key_t set_key
- key ftok("/usr/local/dir1/abc", 4)
- if (key -1)
-
- perror("ftok ")
- exit(1)
-
13Shared Memory
- int SharedMemHandle(int shkey)
- int shm_addr
- int shm_id
- shm_idshmget(shkey, 2048, IPC_CREAT 0600)
- if(shm_id -1)
- perror("shmget ")
- exit(1)
- shm_addrshmat(shm_id, NULL, 0)
- return shm_addr
14Shared Memory
- int counter1, counter2
- int shm
- shmSharedMemHandle(SHMEM_KEY)
- counter1 shm
- counter2 shmsizeof(int)
- // memory management by programmer
- (counter1)0 //and so-on
15Shared Memory
- int memidshmget(SHMEM_KEY, 2048, 0600)
- int memdelshmctl(memid, IPC_RMID, NULL)
- printf("d memory delete status\n", memdel)
-
16Semaphores
- int sem_set_id semget(sem_key, 1, IPC_CREAT
0600) - printf("d\n", sem_set_id)
- if (sem_set_id-1)
- fprintf(stderr, "semget error")
- perror("")
- exit(1)
-
17Semaphores
- int rc semctl(sem_set_id, 0, SETVAL, 1)
- if (rc -1)
- fprintf(stderr, "semctl ")
- perror("")
- exit(1)
-
-
18Semaphores
- union semun sem_val
- sem_val.val 1
- int rc semctl(sem_set_id, 0, SETVAL, sem_val)
- if (rc -1)
- fprintf(stderr, "semctl ")
- perror("")
- exit(1)
-
- union semun
- int val / value for SETVAL /
- struct semid_ds buf / buffer for IPC_STAT
IPC_SET / - u_short array / array for GETALL SETALL /
-
19Semaphores
- int gv semctl(sem_set_id, 0, GETVAL, NULL)
- printf("value of sem_set_id is d\n", gv)
20Semaphores
- int semdel, semid
- semidsemget(sem_key, 1, IPC_CREAT 0600)
- semdelsemctl(semid, 0, IPC_RMID)
- printf("d semaphore delete status\n", semdel)
21Semaphores
- int SemGetID(int which)
- int sem_set_id
- sem_id semget(which, 1, 0600)
- if (sem_set_id -1)
- fprintf(stderr, "semget")
- perror("")
- exit(1)
- return sem_id
-
22Semaphores
- void waitSem(int which)
- int sem_id
- struct sembuf sem_op
- sem_id SemGetID(which)
- printf("execute wait for sem_id d\n", sem_id)
- sem_op.sem_num 0
- sem_op.sem_op -1
- sem_op.sem_flg 0
- semop(sem_id, sem_op, 1)
-
23Semaphores
- void signalSem(int which)
- int sem_id
- struct sembuf sem_op
- sem_id SemGetID(which)
- printf("execute signal for sem_id d\n",
sem_id) - sem_op.sem_num 0
- sem_op.sem_op 1
- sem_op.sem_flg 0
- semop(sem_id, sem_op, 1)
-
24Process p1.c
- int main(void)
- int i
- int counter1, counter2
- int shm
- shmSharedMemHandle(SHMEM_KEY)
- counter1 shm
- counter2 shmsizeof(int)
- //initialize
-
25Semaphores
- for (i0 ilt5 i)
- waitSem(sem_key)
- (counter1)
- (counter2)
- printf("Process 1 increments counter1 d and
counter2 d\n", counter1, counter2) - signalSem(sem_key)
- sleep(2)
-
- //deallocate resources
26- ipcs
- Prints information about active shared memory
segments, message queues and semaphores. - ipcrm
- remove a message queue, semaphore set, or
shared memory ID
27- Solaris implements two flavors of mutex locks,
adaptive and spin. - When a kernel code segment attempts to acquire a
mutex lock, and the lock is being held, the
thread can do one of two things spin or block. - Spinning on a mutex means simply executing a
tight loop, with lock acquisition attempted in
each pass through the loop. - Blocking means putting the thread to sleep.
28- Spinning has the advantage of not requiring a
context switch off the processor, such that, once
the lock is acquired, execution continues. The
downside is that a processor is consumed during
the spin. - Blocking frees up the processor, as the blocked
thread is put to a sleep state and context
switched off the processor, freeing it up for
other work. - It does, however, require the overhead of context
switching the thread back in once the lock is
available.
29- Adaptive mutex locks
- They deal with the above choices in a dynamic
fashion.
30- Adaptive mutex locks
- If a mutex lock is currently owned by another
thread when a kernel thread attempts to acquire
the lock, the state of the thread is examined. - If the thread holding the lock is running, the
kernel thread trying to get the lock will spin,
based on the assumption that the running thread
will release the lock in relatively short order.
31- Adaptive mutex locks
- If the holder is sleeping, then the thread
wanting the lock will also block (sleep), because
it doesn't make sense to consume a processor
spinning and waiting for the holder to wake up
and release the lock.