310 likes | 428 Views
Tuesday, 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. Dining Philosophers Example. monitor dp { enum {thinking, hungry, eating} state[5]; condition self[5]; void pickup(int i)
E N D
Tuesday, 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
Dining Philosophers Example monitor dp { enum {thinking, hungry, eating} state[5]; condition self[5]; void pickup(int i) void putdown(int i) void test(int i) void init() { for (int i = 0; i < 5; i++) state[i] = thinking; } }
Dining Philosophers void pickup(int i) { state[i] = hungry; test[i]; if (state[i] != eating) self[i].wait(); } void putdown(int i) { state[i] = thinking; // test left and right neighbors test((i+4) % 5); test((i+1) % 5); }
Dining Philosophers void test(int i) { if ( (state[(I + 4) % 5] != eating) && (state[i] == hungry) && (state[(i + 1) % 5] != eating)) { state[i] = eating; self[i].signal(); } }
Monitors • Example motorbike …
Low level atomic operations • interrupt disable • Test&Set • Compare&Swap • High level atomic operations • mutex • semaphores • monitors
Three primary mechanisms used for IPC in POSIX • Message queues • Semaphores • Shared memory
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.
shmget system call shm_id=shmget(200, 2048, IPC_CREAT | 0600); Allocate a shared memory segment of 2048 bytes accessible only to current user.
0400 user may read from this resource • 0200 user may write to this resource • 0040? • 0002?
ftok() 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.
ftok() system call - generate an IPC key key_t set_key; key = ftok("/usr/local/dir1/abc", 4); if (key == -1) { perror("ftok: "); exit(1); }
Shared Memory int* SharedMemHandle(int shkey){ int* shm_addr; int shm_id; shm_id=shmget(shkey, 2048, IPC_CREAT | 0600); if(shm_id == -1){ perror("shmget: "); exit(1); } shm_addr=shmat(shm_id, NULL, 0); return shm_addr; }
Shared Memory int* counter1, *counter2; int* shm; shm=SharedMemHandle(SHMEM_KEY); counter1 = shm; counter2 = shm+sizeof(int); // memory management by programmer (*counter1)=0; //and so-on
Shared Memory int memid=shmget(SHMEM_KEY, 2048, 0600); int memdel=shmctl(memid, IPC_RMID, NULL); printf("%d memory delete status\n", memdel);
Semaphores intsem_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); }
Semaphores int rc = semctl(sem_set_id, 0, SETVAL, 1); if (rc == -1) { fprintf(stderr, "semctl: "); perror(""); exit(1); }
Semaphores 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 */ };
Semaphores int gv = semctl(sem_set_id, 0, GETVAL, NULL); printf("value of sem_set_id is %d\n", gv); }
Semaphores int semdel, semid; semid=semget(sem_key, 1, IPC_CREAT | 0600); semdel=semctl(semid, 0, IPC_RMID); printf("%d semaphore delete status\n", semdel);
Semaphores 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; }
Semaphores 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); }
Semaphores 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); }
Process p1.c int main(void){ int i; int* counter1, *counter2; int* shm; shm=SharedMemHandle(SHMEM_KEY); counter1 = shm; counter2 = shm+sizeof(int); //initialize;
Semaphores for (i=0; i<5; 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 }
ipcs • Prints information about active shared memory segments, message queues and semaphores. • ipcrm • remove a message queue, semaphore set, or shared memory ID
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.
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 switchingthe thread back in once the lock is available.
Adaptive mutex locks • They deal with the above choices in a dynamic fashion.
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.
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.