64
Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Embed Size (px)

DESCRIPTION

Schedule of Lectures, Projects and Homeworks Lecture 13 Project 4 Due Day Project 5 HW#4 Due Day Tutorial for Project5 Project 5 Due Day final exam. week

Citation preview

Page 1: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Lecture 8 Pipe,

Signal,Semaphore

(Homework #3 included)

Nov. 3, 2015Kyu Ho Park

Page 2: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Schedule ofLectures, Projects and Homeworks

Lec-ture 9HW#3Lecture 10HW#3 Due

Project 3Due DayLecture

11Project 4Lecture 12HW#4

Page 3: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Schedule ofLectures, Projects and Homeworks

Lecture 13Project 4 Due Day

Project 5HW#4 Due Day

Tutorialfor Project5

Project 5Due Day

final exam. week

Page 4: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

IPC in Linux Pipe(FIFO File) Signal Semaphore Shared memory Message queues

Page 5: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

$command1 | command2

com-mand 1 screencom-

mand 2 pipeKeyboard

Standard output

Standard input

Page 6: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Pipe#include <unistd.h>int pipe(int filedes[2]); filedes: file descriptors, filedes[0] for reading ,

filedes[1] for writing. return value: 0 when successful, -1 when failed.

Page 7: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Characteristics of PIPE If the pipe is empty, the reading process is

blocked to sleep. If there is a blocked process for read, writing to

the pipe wakes up the reader process. Therefore pipe has two functions, ( ?) and ( ?).

Page 8: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

pipe#include <stdio.h>#include <unistd.h>#include <stdlib.h>

void error_exit(char * message);

int main(void){ int fd[2]; int fd_in, fd_out; int n; char buf[10]="message";

if( pipe(fd) == -1) exit(1);

if( fork()==0) { fd_in=open("input",0); if(fd_in ==-1) exit(1);

close(fd[0]);

while( (n=read(fd_in,buf, 10)) !=0) write(fd[1], buf, n);

close(fd_in); close(fd[1]);

exit(0); }

else { close(fd[1]); fd_out = creat("output",0666); if(fd_out ==-1) error_exit("creat");

while((n=read(fd[0], buf, 10)) !=0) write(fd_out, buf,n);

close(fd_out); close(fd[0]); wait(); }

return 0;}

void error_exit(char *message){ fprintf(stderr, "%s\n", message); exit(-1);}

root@ubuntu:~/Test/FIFO# ./pipecopy < input >outputroot@ubuntu:~/Test/FIFO# more outputHelloAgain!

Page 9: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

buf buf Pipe

fd[1] fd[0]input

out-put

Child process

Parent process

Page 10: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Named Pipe: FIFO#include <sys/types.h>#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode); pathname: FIFO path name, mode: FIFO file access permission, return value: 0 if successul, -1 if failed.

FIFO is a special file and its function is nearly the same as the pipe. The pipe is a communication channel with-out any name but FIFO is registered special file by mkfifo systemcall.

Page 11: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

FIFO example#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>

int main(){

int res = mkfifo(“/home/kpark/my_fifo”, 0777);if( res ==0) printf( “FIFO is created\n”);exit(1);

}

Page 12: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Read and write using FIFO#include <fcntl.h>#include <sys/stat.h>#include <unistd.h>#define MSGSIZE 64main(){ char msg[MSGSIZE]; int filedes; int nread, cnt; if(mkfifo("./fifo", 0666) == -1) { printf("fail to call fifo()\n");

exit(1); } if((filedes = open("./fifo", O_RDWR)) < 0) {

printf("fail to call fifo()\n");exit(1);

} for(cnt = 0; cnt < 3; cnt++) {

if((nread = read(filedes, msg, MSGSIZE)) < 0)

{ printf("fail to call read()\n"); exit(1);}printf("recv: %s\n", msg);

}unlink("./fifo");

}

#include <fcntl.h>#include <sys/stat.h>#include <unistd.h>#define MSGSIZE 64main(){ char msg[MSGSIZE]; int filedes; int cnt; if((filedes = open("./fifo", O_WRONLY)) < 0) { printf("fail to call open()\n"); exit(1); } for(cnt = 0; cnt < 3; cnt++) { printf("input a message: "); scanf("%s", msg); if(write(filedes, msg, MSGSIZE) == -1) { printf("fail to call write()\n"); exit(1); } sleep(1); }}

read_fifo.c write_fifo.c

Page 13: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Signals

2015. 9.1 Kyu Ho Park

CORE Lab.

Embedded Software

Page 14: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

SIGNALS

14

Page 15: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

signals Signals are software interrupt and

provide a basic method of interpro-cess communication.

The generation of a signal is occurred by some error conditions(memory segment violations, floating-point processor errors) and illegal instruc-tions.

15

Page 16: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Signal sending Two functions for raising signals: #include <sys/types.h> #include <signal.h>

int kill(pid_t pid, int sig); int raise(int sig); kill( ) can send any signal to any process group or

process. raise() is used for a process to send a signal to it-

self. It is equivalent to kill(getpid(), sig).

16

Page 17: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

kill() process selection When pid > 0 :signal sent to process with proc_id = pid. pid = 0 :sent to all processes whose process group id is the same as the sender for whom the sender has permission. pid < -1 : sent to all processes whose process group id is the absoluter value of pid and for whom the sender has permission. pid = -1: sent to every process except for the first one , from higher numbers in the process table to lower.

17

Page 18: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

18

Page 19: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Alarm, pause and sleep #include <unistd.h> unsigned int alarm(unsigned int seconds);

/*After the expiration of an assigned time, it sends SIGALARM to itself */ #include <unistd.h> int pause(void);

/*pause until a signal received, return value is always -1 */ unsigned int sleep(unsigned int seconds);

19

Page 20: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

sigPause.c

20

Page 21: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Signal handler #include <signal.h> (void) signal(SIGINT, handler );The signal handler is set to handler() which may be a user specified function or one of {SIG_IGN, SIG_DFL}.

21

Page 22: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

22

Page 23: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Typical Signal Handling1. #include <signal.h>2. #include <stdio.h>3. #include <unistd.h>4. void handler(int sig)5. { printf(“I received a signal %d\n”, sig);}

6. int main()7. { struct sigaction act;8. sigemptyset(&act.sa_mask);9. act.sa_handler=handler;10. sigaction(SIGINT,&act,0);11. while(1) {12. printf(“Hello EE516!\n”);13. sleep(1);14. }15. }16.

23

struct sigaction{ void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags;}

Page 24: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park
Page 25: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

sigfillset(),sigemptyset(),sigaddset(), sigdelset(),and sigismember()

#include <signal.h>int sigfillset(sigset_t *set); //fill the set with all signals.int sigemptyset(sigset_t *set); //empty the set.int sigaddset(sigset_t *set, int signum);//signum is the signal number

Page 26: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

sigaction( )#include <signal.h>int sigaction(int signum, const struct sigaction *act,

struct sigaction *oldact);

/*act: action to do for the signal .oldact: previously determined action for the signal, normally set to NULL.*/

struct sigaction{ void (*sa_handler)(int);//function, SIG_DFL, or SIG_IGN void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; //signals to block in sa_handler int sa_flags; //signal action modifiers}

Page 27: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

sigprocmask( )#include <signal.h>int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

/*how={SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK}*/

Page 28: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Semaphore

Page 29: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Synchronization with semaphoresTwo set of functions for sepaphore:

- POSIX semaphore functions for threads,

- System V semaphore functions for processes.

Page 30: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

POSIX semaphore#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);- sem: points to a semaphore object, pshared: if 0, the semaphore is local to the current process, else the semaphore may be shared be-tween processes(Linux does not support it). value: initial value of the semaphore.

int sem_wait(sem_t *sem);-This function waits until the semaphore is nonzero, and decreases the value of semaphore by 1.

int sem_post(sem_t *sem);-This function increases the value of the semaphore by 1.

int sem_destroy(sem_t *sem);

30

Page 31: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

System V semaphoreSemaphore Definition:

P(sem) : If sem is greater than 0, decrement sem,

If sem is zero, suspend execution of this process.

V(sem) : If some other process has been sus-pended waiting for sem, make it resume execution. If no process is suspended waiting for sem, increment sem. // sem = semmaphore variable.

Page 32: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semget( )#include <sys/sem.h>

int semget(key_t key, int num_sems, int sem_flags);key: an integer value used to allow unrelated pro-

cesses to access the same semaphore. The key is used only with semget. All other semaphore functions use the semaphore identifier(sem_id) returned from semget.

num_sems: the number of semaphores.

sem_flags: IPC_CREAT | IPC_EXCL

return value: positive integer which is the semaphore identifier, -1 on error.

Page 33: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semop()int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops); This function is used for changing the value of the semaphore.

sem_id: the value returned from semget.sem_ops: a pointer to an array of structure sembuf as belowstruct sembuf {short sem_num; // 0 usuallyshort sem_op; // -1 for P operation, +1 for V // op-

eration.short sem_flg; //usually SEM_UNDO}

Page 34: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semctl( )int semctl(int sem_id, int sem_num, int command, ..); This function allows direct control of semaphore information.

command: To remove the semaphore set, cmd should be set to IPC_RMID. In this case sem_num and arg have no meaning.

To initialize a semaphore to a known value, cmd should be set to SETVAL.

semctl(semid, 0, IPC_RMID, dummy);

Page 35: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

set_semaphore example/* The function set_semvalue initializes the semaphore using the SETVAL command in a semctl call. We need to do this before we can use the sema-phore. */

static int set_semvalue(void){ union semun sem_union;

sem_union.val = 1; if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0); return(1);}

Page 36: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

del_semaphre example/* The del_semvalue function has almost the same form, except the call to semctl uses the command IPC_RMID to remove the semaphore's ID. */

static void del_semvalue(void){ union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) fprintf(stderr, "Failed to delete semaphore\n");}

Page 37: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semaphore_p example/* semaphore_p changes the semaphore by -1 (waiting). */

static int semaphore_p(void){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; /* P() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_p failed\n"); return(0); } return(1);}

Page 38: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semaphore_v example/* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1, so that the semaphore becomes available. */

static int semaphore_v(void){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; /* V() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_v failed\n"); return(0); } return(1);}

Page 39: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

semun.h#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including <sys/sem.h> */#else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ };#endif

Page 40: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Homework #3 At the last part of the printed handout ‘System V

IPC(Semaphore), there are three sample programs semi-nit.c, semdemo.c, and semrm.c.

Task 1: analyze those three programs and explain the behavior of each program and their expected output of each programs.

Task 2: make run those programs suggested at the sec-tion ‘Sample programs’ and show each output of those programs.

Due: Nov.10, 23:59. Other guidelines are the same as the previous homeworks.

Submit it to Joo Kyung Ro, [email protected])

Page 41: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

41

Supplement to IPC:

Page 42: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

42

Interprocess Communica-tion

Processes:Independent Processes or Cooperat-

ing Processes IPC issues:

1. How one process can pass information to an-other.

2. Mutual Exclusion.3. Proper sequencing when dependencies are

present.

42

Page 43: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Interprocess Communication(IPC)

process A

process B

kernel

M

M

M

12

process A

shared

process B

kernel

1

2

Message Pass-ing

Shared Mem-ory

Page 44: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

44

Producer-Consumer Problem Paradigm for cooperating pro-

cesses, producer process pro-duces information that is con-sumed by a consumer process unbounded-buffer places no

practical limit on the size of the buffer

bounded-buffer assumes that there is a fixed buffer size

Page 45: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Message Passing (1) Figure 2-17. The producer-consumer

problem with N messages.

. . .

Page 46: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Message Passing (2) Figure 2-17. The producer-consumer

problem with N messages.

. . .

Page 47: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Message Passing Message system – processes communicate with each

other without resorting to shared variables Message passing facility provides two operations:

send(message) – message size fixed or variable receive(message)

If P and Q wish to communicate, they need to: establish a communication link between them exchange messages via send/receive

Implementation of communication link physical (e.g., shared memory, hardware bus) logical (e.g., logical properties)

Page 48: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Implementation Questions How are links established? Can a link be associated with more than

two processes? How many links can there be between

every pair of communicating processes? What is the capacity of a link? Is the size of a message that the link

can accommodate fixed or variable? Is a link unidirectional or bi-directional?

Page 49: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Direct Communication Processes must name each other explicitly:

send (P, message) – send a message to process P receive(Q, message) – receive a message from

process Q Properties of communication link

Links are established automatically A link is associated with exactly one pair of com-

municating processes Between each pair there exists exactly one link The link may be unidirectional, but is usually bi-di-

rectional

Page 50: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Indirect Communication Messages are directed and received from mail-

boxes (also referred to as ports) Each mailbox has a unique id Processes can communicate only if they share

a mailbox Properties of communication link

Link established only if processes share a common mailbox

A link may be associated with many processes Each pair of processes may share several

communication links Link may be unidirectional or bi-directional

Page 51: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Indirect Communication Operations

create a new mailbox send and receive messages through mailbox destroy a mailbox

Primitives are defined as:send(A, message) – send a message to mailbox Areceive(A, message) – receive a message from mailbox A

Page 52: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Indirect Communication Mailbox sharing

P1, P2, and P3 share mailbox A P1, sends; P2 and P3 receive Who gets the message?

Solutions Allow a link to be associated with at most two

processes Allow only one process at a time to execute a re-

ceive operation Allow the system to select arbitrarily the receiver.

Sender is notified who the receiver was.

Page 53: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Synchronization Message passing may be either blocking or non-

blocking Blocking is considered synchronous

Blocking send has the sender block until the message is received

Blocking receive has the receiver block until a message is available

Non-blocking is considered asynchronous Non-blocking send has the sender send the

message and continue Non-blocking receive has the receiver receive

a valid message or null

Page 54: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Buffering Queue of messages attached to the

link; implemented in one of three ways1. Zero capacity – 0 messages

Sender must wait for receiver (rendezvous)2. Bounded capacity – finite length of n

messagesSender must wait if link full

3. Unbounded capacity – infinite length Sender never waits

Page 55: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Bounded-Buffer – Message Passing Solution

The Producer

Channel mailBox;

while (true) {Date message = new Date();mailBox.send(message);

}

Page 56: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Bounded-Buffer – Message Passing Solution

The ConsumerChannel mainBox;

while (true) {Date message = (Date) mailBox.re-

ceive();if(message != NULL)

/*consume the message */}

Page 57: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitors A high-level abstraction that

provides a convenient and ef -fective mechanism for process synchronization

Only one process may be ac-tive within the monitor at a time

Page 58: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Schematic view of a Monitor

P1

P2

P3

P6

P4

Critical Data

Condition C

Condition D

Wait-ing Sig-nalers

Entry E

Entry F

Entry G

P5

Fence

Page 59: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Condition Variables Condition c, d; Two operations on a condi-

tion variable: c.wait () – a process that in-

vokes the operation is sus-pended.

c.signal () – resumes one of processes (if any) that in-voked c.wait ()

Page 60: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitor with Condition Variables

P1

P2

P3

P6

P4

Critical Data

Condition C

Condition D

Wait-ing Sig-nalers

Entry E

Entry F

Entry G

P5

Fence

Page 61: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitor with Condition Variables

P1

P2

P6

P5

P4

Critical Data

Condition C

Condition D

Waiting Sig-nalers

Entry E

Entry F

Entry G P3

Fence

Page 62: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitors (1)

Page 63: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitors (2)

Page 64: Lecture 8 Pipe, Signal, Semaphore (Homework #3 included) Nov. 3, 2015 Kyu Ho Park

Monitors (3)