inter process synchronization and communication ct213 – computing systems organization

76
Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Upload: hanna-harbold

Post on 14-Dec-2015

221 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Inter Process Synchronization and Communication

CT213 – Computing Systems Organization

Page 2: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Content • Parallel computation• Process interaction

– Processes unaware of each other– Processes indirectly aware of each other– Processes directly aware of each other

• Critical sections• Mutual exclusion

– Software approaches (Dekker Algorithm, Peterson’s Algorithm)– Hardware approaches (Interrupt disabling, ISA modification)

• Semaphores & mutual exclusion with semaphores• Producer Consumer problems• Semaphores implementation

• Messages & design issues

• Readers/Writers problem

Page 3: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Parallel Computation

• Is made up from multiple, independent parts that are able to execute simultaneously using one part per process or thread– In some cases, different parts are defined by one

program, but in general they are defined by multiple programs;

– Cooperation is achieved through logically shared memory that is used to share information and to synchronize the operation of the constituent processes

• The operating system should provide at least a base level mechanism to support sharing and synchronization among a set of processes

Page 4: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Operating System Concerns

• Keep track of active processes – done using process control block

• Allocate and de-allocate resources for each active process (Processor time, Memory, Files, I/O devices)

• Protect data and resources against unwanted interference from other processes– Programming errors done in one process should not affect the

stability of other processes in the system

• Result of process must be independent of the speed of execution of other concurrent processes– This includes process interaction and synchronization and it is

subject of this presentation

Page 5: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Process Interaction• Processes unaware of each other

– Independent processes that are not intended to work together; i.e. two independent applications want to access same printer or same file; the operating system must regulate these accesses; these processes exhibit competition

• Processes indirectly aware of each other– Processes that are not aware of each other by knowing each

other’s process ID, but they are sharing some object (such as an I/O buffer); such processes exhibit cooperation

• Process directly aware of each other– These are processes that are able to communicate to each other

by means of process IDs; they are usually designed to work jointly on some activity; these processes exhibit cooperation

Page 6: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Competition Among Processes for Resources

• Two or more processes need to access a resource– Each process is not aware of the existence of the other– Each process should leave the state of the resource it uses unaffected (I/O devices,

memory, processor, etc)• Execution of one process may affect the execution of the others

– Two processes wish access to single resource– One process will be allocated the resource, the other one waits (therefore slowdown)– Extreme case: waiting process may never get access to the resource, therefore never

terminate successfully • Control problems:

– Mutual Exclusion• Critical sections

– Only one program at a time is allowed in a critical section– i.e. only one process at a time is allowed to send command to the printer

– Deadlock• P1 and P2 with R1 and R2; each process needs to access both resources to perform part of

its function; R1 gets allocated to P2 and R2 gets allocated to P1 … both processes will wait indefinitely for the resources … deadlock

– Starvation• P1, P2, P3 and resource R … P1 and P3 take successively access to resource R … P2 may

never get access to it, even if there is no deadlock situation … starvation

Page 7: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Cooperation Among Processes by Sharing

• Processes that interact with other processes without being aware of them– i.e. multiple processes that have access to global variables,

shared files or databases– The control mechanism must ensure the integrity of the shared

data

• Control problems:– Deadlock– Starvation– Mutual exclusion– Data coherence

• Data items are accessed in two modes: read and write• Writing must be mutually exclusive to shared resources• Critical sections are used to provide data integrity

Page 8: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Cooperation Among Processes by Communication

• When processes cooperate by communication, various processes participate in a common effort that links all of the processes– Communication provides a way to sync or coordinate the

various activities• Communication can be characterized by

sending/receiving messages of some sort– Mutual exclusion is not a control requirement since nothing is

shared between process in the act of passing messages• Control problems:

– Possible to have deadlock• Each process waiting for a message from the other process

– Possible to have starvation• Two processes sending message to each other while another process

waits for a message

Page 9: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Example of Communication by Sharing problems

• Process 1 KEYBOARD:– Services the keyboard interrupts – The read characters are placed in a keyboard buffer

• Process 2 DISPLAY– Displays the content of buffer on the monitor

• Shared resources:• Input buffer

• Characters counter of how many chars in buffer and not displayed

Page 10: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

KEYBOARD and DISPLAY processes

• If KEYBOARD process is interrupted after instruction “1” (its registers (context) are saved and restored when gains the control of the CPU back) and the control passed to the process DISPLAY, the value of the counter variable will be altered, the two processes will continue to function improperly from this time forward …

• Causes for malfunction:– The presence of two copies of same counter variable, one in memory and one in AC

with different values– Parallel execution of the two processes

• Situations where two or more processes are reading or writing some shared data and the final result depends on who runs precisely when, are called race conditions

Keyboard Process

1. ld AC, counter2. inc AC3. store AC, counter4. …5. …

Display process

1. ld AC, counter2. dec AC3. store AC, counter4. …5. …

Page 11: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Critical Sections• Are parts of the code (belonging to a process) that during

execution has exclusive control over a system resource • It has a well defined beginning and end• During the execution of the critical section, the process

can’t be interrupted and the control of the processor given to another process that is using same system resource

• At a given moment, there is just one active critical section corresponding to a given resource

• A critical section is executed in mutual exclusion mode• Critical section examples:

– Value update for a global shared variable– Modification of a shared database record– Printing to a shared printer

Page 12: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Mutual Exclusion• If we could arrange matters so no two processes were ever in

their critical regions at the same time, we could avoid race conditions

• This requirement avoids race conditions, but is not sufficient for having parallel processes cooperate correctly and efficiently using shared data. Four conditions to achieve good results:

1. No two processes may be simultaneously inside their critical regions (have mutual exclusion)

2. No assumption may be made about speeds and number of CPUs (independence of speed and number of processors)

3. No process outside critical section may block other processes (correct functionality is to be guaranteed if one of the processes is abnormally terminated outside of the critical section)

4. No process would have to wait forever to enter its critical section (the access in the critical section is guaranteed in a finite time)

Page 13: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Mutual Exclusion

• While one process is busy updating shared memory (or modifying a shared resource) in its critical region, no other process will enter its critical region and cause trouble

• There are a number of different approaches:– Software approaches

• Dekker Algorithm

• Peterson’s Algorithm

– Hardware approaches• Interrupt disabling

• ISA modification

Page 14: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Dekker’s Algorithm – First Attempt

• turn – global memory location that both processes could access; each process examines the value of turn, if it is equal to the number of process, then the process could proceed to the critical section

• This procedure is known as busy waiting, since the processes are waiting (doing nothing productive but taking processor) to get the access to critical section

• Mutual exclusion conditions:1. Satisfied2. Unsatisfied – processes can be executed alternatively only, thus, the rhythm of execution is

given by the slower process3. Unsatisfied – abnormal termination of one process determines blocking of the other4. Satisfied

void proc1(){ while (TRUE){ while (turn ==PROC2){;} /*critical section code */ turn = PROC2; something_else(); }}

void proc2(){ while (TRUE){ while (turn ==PROC1){;} /*critical section code */ turn = PROC1; something_else(); }}

int turn; /*global variable*/

main(){turn = PROC1;init_proc(&proc1(), …); init_proc(&proc2(), …);}

Page 15: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Dekker’s Algorithm – Second Attempt

• The problem with first attempt is that it stores the name of the process that may enter its critical section, when in fact we need state information about both processes

• Each process has to have its key to the critical section, so if one process fails, the other could still have access to the critical section

• Mutual exclusion conditions:1. Unsatisfied – if process proc1 is getting interrupted right before have set p1use = TRUE, and

the second process takes over the processor, then at one stage both processes will have access to the critical section

2. Satisfied3. Satisfied if the processes are not failing in the critical section or during setting the flags4. Satisfied

void proc1(){ while (TRUE){ while (p2use ==TRUE){;} p1use = TRUE; /*critical section code */ p1use = FALSE; something_else(); }}

void proc2(){ while (TRUE){ while (p1use ==TRUE){;} p2use = TRUE; /*critical section code */ p2use = FALSE; something_else(); }}

/*global variables*/int p1use, p2use;

main(){p1use = FALSE;p2use = FALSE;init_proc(&proc1(), …); init_proc(&proc2(), …);}

Page 16: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Dekker’s Algorithm – Third Attempt

• Because one process could change its state after the other checked it, both processes could go in the critical section, so the second attempt failed

• Perhaps we could change this with just changing the position of two statements …

• Mutual exclusion conditions:1. Satisfied2. Satisfied3. Satisfied if the processes are not failing in the critical section or during setting the

flags; Unsatisfied otherwise (the other process is blocking)4. Unsatisfied – if both processes set their flags to true before either of them has

executed the while statement, then each will think that the other has entered its critical section, causing deadlock

void proc1(){ while (TRUE){ p1use = TRUE; while (p2use ==TRUE){;}/*critical section code */ p1use = FALSE; something_else(); }}

void proc2(){ while (TRUE){ p2use = TRUE; while (p1use ==TRUE){;} /*critical section code */ p2use = FALSE; something_else(); }}

int p1use, p2use; /*global variables*/main(){p1use = FALSE;p2use = FALSE;init_proc(&proc1(), …); init_proc(&proc2(), …);}

Page 17: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Dekker’s Algorithm – Forth Attempt

• Third algorithm failed because deadlock occurred as result of irreversibly change of each process’s state to TRUE before actually having the test done. No way back off from this position

• Try to fix this by having each process to indicate its desire to enter the critical section, but it is prepared to defer to the other process

• Mutual exclusion conditions:1. Satisfied2. Unsatisfied – if the processes are executing with exact speed, then neither of the processes

will enter the critical section3. Satisfied if the processes are not failing in the critical section or during setting the flags;

Unsatisfied otherwise (the other process is blocking)4. Satisfied

void proc1(){ while (TRUE){ p1use = TRUE; while (p2use ==TRUE){ p1use = FALSE; delay(…); p1use = TRUE; }/*critical section code */ p1use = FALSE; something_else(); }}

void proc2(){ while (TRUE){ p2use = TRUE; while (p1use ==TRUE){ p2use = FALSE; delay(…); p2use = TRUE; } /*critical section code */ p2use = FALSE; something_else(); }}

int p1use, p2use; /*global variables*/main(){p1use = FALSE;p2use = FALSE;init_proc(&proc1(), …); init_proc(&proc2(), …);}

Page 18: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Dekker’s Algorithm – Correct Version

• It is an algorithm that respects the 4 conditions of mutual exclusion, but only for two concurrent processes.

• Mutual exclusion conditions:1. Satisfied2. Satisfied 3. Satisfied 4. Satisfied

void proc1(){ while (TRUE){ p1use = TRUE; while (p2use ==TRUE){ if (turn == PROC2){ p1use = FALSE; while (turn ==PROC2){;} p1use = TRUE; } } /*critical section*/ turn = PROC2; p1use = FALSE; something_else(); }}

void proc2(){ while (TRUE){ p2use = TRUE; while (p1use ==TRUE){ if (turn == PROC1){ p2use = FALSE; while (turn ==PROC1){;} p2use = TRUE; } } /*critical section code */ turn = PROC1 p2use = FALSE; something_else(); }}

int p1use, p2use, turn; /*global variables*/

main(){p1use = FALSE;p2use = FALSE;turn = PROC1;init_proc(&proc1(), …); init_proc(&proc2(), …);}

Page 19: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Peterson’s Algorithm

• If proc2 is in its critical section, then p2use = TRUE and proc1 is blocked from entering its critical section.

• Peterson’s Algorithm can be easily generalized for n threads

• Mutual exclusion conditions:1. Satisfied2. Satisfied 3. Satisfied 4. Satisfied

void proc1(){ while (TRUE){ p1use = TRUE; turn = PROC2; while (p2use ==TRUE && turn==PROC2){;} /*critical section*/ p1use = FALSE; something_else(); }}

int p1use, p2use; int turn;

main(){p1use = FALSE;p2use = FALSE;init_proc(&proc1(), …); init_proc(&proc2(), …);}

void proc2(){ while (TRUE){ p2use = TRUE; turn = PROC1; while (p1use ==TRUE && turn==PROC1){;} /*critical section*/ p1use = FALSE; something_else(); }}

Page 20: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Hardware Solutions - Disabling Interrupts• Simplest solution is to have the process disable interrupts right

after entering the critical region and enable them just before leaving it– With interrupts disabled, no interrupts will occur;– The processor is switched from process to process only as result of interrupt

occurrence, so the processor will not be switched to other process• It is unwise to give a user process the power to turn off interrupts

– Suppose it did it and never turn them on again …– Suppose it is a multi-processor system …disabling interrupts on one of

them, will not help too much• It is a useful technique within the operating system itself, but it is

not appropriate as general mutual exclusion mechanism for user processes

while (TRUE){ /*disable interrupts*/ /*critical section*/ /*enable interrupts*/ something_else();}

Page 21: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Special Machine Instructions• In a multiprocessor configuration, several processors

share access to a common main memory; the processors behave independently

• There is no interrupt mechanism between processors on which mutual exclusion can be based

• At a hardware level, access to a memory location excludes any other access to same memory location; based on this, several machine level instructions to help mutual exclusion have been added. Most common ones:– Test & Set Instruction– Exchange Instruction

• Because those operations are performed in a single machine cycle, they are not subject to interference from other instructions

Page 22: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Test & Set Instruction

• The shared variable bolt is initialized to 0; • The only process that may enter its critical section is the one that finds the bolt

variable equal to 0• All processes that attempt to enter the critical section go into a busy waiting

mode• When a process leaves the critical section, it resets bolt to 0; at this point only

one from the waiting processes is granted access to the critical section

/*test & set instruction */boolean testset (int i) { if (i==0){ i=1; return TRUE; } else{ return FALSE; }}

void proc(int i){ while (TRUE){ while (!testset(bolt)){;} /*critical section*/ bolt = 0; something_else(); }}

/*number of processes*/const int n = 2; int bolt;main(){ int i; i=n; bolt = 0; while (i >0){ init_proc(&proc1(i), …); i--; }}

Page 23: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Exchange Instruction

• The instruction exchanges the contents of a register with that of a memory location; during the execution of the instruction, access to that memory location is blocked for any other instruction

• The shared variable bolt is initialized to 0; each process holds a local variable key that is initialized to 1

• The only process that enters the critical section is the one that finds the variable bolt equal to 0;

/*exchange instruction */void exchange (int register, int memory) { int temp; temp = memory; memory = register; register = temp; }

void proc(int i){ int keyi; while (TRUE){ keyi=1; while (keyi != 0){ exchange(keyi, bolt); } /*critical section*/ exchange (keyi, bolt); something_else(); }}

/*number of processes*/const int n = 2; int bolt;main(){ int i; i=n; bolt = 0; while (i >0){ init_proc(&proc1(i), …); i--; }}

Page 24: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Properties of Hardware Approach• Advantages:

– Simple and easy to verify– It is applicable to any number of processes on either a single processor or

multiple processors sharing main memory– It can be used to support multiple critical sections, each critical section

defined by its own global variable

• Problems:– Busy waiting is employed – Starvation is possible – selection of a waiting process is arbitrary, thus some

process could indefinitely be denied access– Deadlock is possible – consider following scenario:

• P1 executes special instruction (test&exchange) and enters its critical section• P1 is interrupted to give the processor to P2 (which has higher priority)• P2 wants to use same resource as P1 so wants to enter critical section so, it will

test the critical section variable and wait• P1 will never be dispatched again because it is of lower priority than another

ready process, P2

Page 25: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores

• Because of the drawback of both the software and hardware solutions, we need to look into other solutions

• Dijkstra defined semaphores– Two or more processes can cooperate by means of

simple signals, such that a process can be forced to stop at a specific place until it has received a specific signal

– For signaling, special variables, called semaphores are used

Page 26: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores

• Special variable called a semaphore is used for signaling– to transmit a signal, execute signal(s)

• Dijkstra used V for signal (increment - verhogen in Dutch)

– to receive a signal, execute wait(s)• Dijkstra used P for wait (test - proberen in Dutch)

• If a process is waiting for a signal, it is suspended until that signal is sent

• Wait and Signal operations cannot be interrupted• A queue is used to hold processes waiting on the

semaphore

Page 27: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores – Simplified view

• We can view the semaphore as a variable that has an integer value; three operations are defined upon this value:– A semaphore may be initialized to a non-negative

value– The wait operation decrements the semaphore value. If

the value becomes negative, then the process executing wait is blocked

– The signal operation increments the semaphore value. If the value is not positive, then a process blocked by a wait operation is unblocked

Page 28: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores – Formal view

• A queue is used to hold processes waiting on a semaphore– What order should the

processes be removed• Fairest policy is FIFO, a

semaphore that implements this is called strong semaphore

• A semaphore that doesn’t specify the order in which processes are removed from the queue is known as week semaphore

struct semaphore { int count; queueType queue;}void wait(semaphore s){ s.count--; if (s.count < 0) { place this process in s.queue; block this process }}void signal(semaphore s){ s.count++; if (s.count <= 0) { remove a process P from s.queue; place process P on ready list; }}

Page 29: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Binary Semaphores

• A more restrictive version of semaphores

• A binary semaphore may take on the values 0 or 1.

• In principle it should be easier to implement binary semaphores and they have expressive power as the general semaphore

• Both semaphores and binary semaphores do have a queue to hold the waiting processes

struct binary_semaphore { enum (zero, one) value; queueType queue;};void waitB(binary_semaphore s){ if (s.value == 1) s.value = 0; else{ place this process in s.queue; block this process; }}void signalB(semaphore s){ if (s.queue.is_empty()) s.value = 1; else{ remove a process P from s.queue; place process P on ready list; }}

Page 30: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Example of Semaphore Mechanism

• Processes A, B and C depend on the results from process D

• Initially, process D has produced an item of its resources and it is available (the value of the semaphore is s=1)

Page 31: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

• (1) A is running, B, D and C are ready; When A issues a wait(s) it will immediately pass the semaphore and will be able to continue its execution, so it rejoins the ready queue

• (2) B runs and will execute a wait(s) primitive and it is suspended (allowing D to run)

• (3) D completes a new result and issues a signal(s)

Page 32: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

• (4) signal(s) from (3) allows B to move in ready queue; D rejoins the ready queue and C is allowed to run

• (5) C is suspended when it issues a wait(s), similarly A and B are suspended on the semaphore

• (6) D takes processor again and produces one reslut again, calling signal(s);• (7) C is removed from the semaphore queue and placed in ready list• Latter cycles of D will release A and B from suspension

Page 33: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Mutual Exclusion with Semaphores/* program mutual exclusion */

const int n = 3; /* number of processes */;semaphore lock = 1;

void P(int i){ while (true){ waitB(lock); /* critical section */; signalB(lock); /* other processing*/; }}

void main(){int i;i=n;while (i>0){ init_proc(&proc(i), …); i--; }}

Page 34: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Producer/Consumer Problem

• Problem formulation:– One or more producers generating some type of data

(i.e. records, characters, etc…) and placing these in a buffer

– Consumer that are taking items out of the buffer, one at a time; only one agent (either producer or consumer can access the buffer at a time)

– The system is to be constrained to prevent the overlap of buffer operations

• Examine a number of solutions to this problem

Page 35: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Infinite linear array bufferproducer:

while (true) {

/* produce item v */

Buff[in] = v;

in++;

}

consumer:while (true) { while (in <= out) {;}/*do nothing */;

w = Buff[out];out++; /* consume item w */

}

Note: shaded area indicates occupied locations

• Consumer has to make sure that will not read data from an empty buffer (makes sure in >out)•Try to implement this using binary semaphores

Buff[0] Buff[3] Buff[4] Buff[5]

out in

Buff[1] Buff[2] ...

Page 36: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

One producer, One consumer, Infinite buffer

• product is a semaphore that counts the number of objects placed in the buffer and not consumed yet

• Product is (in – out) (see the previous buffer)

• This solution works only if there is just one consumer, one producer and the intermediary buffer is infinite. If multiple producers/consumers than the append() and take() need to be serialized (as they increment/decrement buffer pointers)

void producer(){ while (TRUE){ produce_object(); append(); signal(product); something_else(); }}

main(){create_semaphore(product);init_proc(&producer(), …); init_proc(&consumer(), …);}

void consumer{ while (TRUE){ wait(product); take(); consume_object(); something else(); }}

Page 37: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Multiple producers, Multiple consumers and infinite buffer

• buff_access_prod is a semaphore that synchronizes the access of producers to the buffer

• buff_access_cons is a sempahore that synchronizes the access of the consummers to the buffer

• product is a semaphore that counts the produced objects yet unconsumed

void producerX(){ while (TRUE){ produce_object(); wait(buff_access_prod); append(); signal(buff_access_prod); signal(product); something_else(); }}

main(){create_semaphore(product);create_semaphore(buff_access_prod);create_semaphore(buff_access_cons);init_proc(&producer1(), …); init_proc(&producer2(), …); /*…*/init_proc(&producerN(), …); init_proc(&consumer1(), …);init_proc(&consumer2(), …);/*…*/init_proc(&consumerM(), …);}

void consumerY{ while (TRUE){ wait(product); wait(buff_access_cons); take(); signal(buff_access_cons); consume_object(); something else(); }}

Page 38: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Finite (circular) bufferproducer:

while (true) {

/* produce item v */

/* do nothing while buffer full */;

while ((in + 1)%n==out){;}

Buff[in] = v;

in = (in + 1) % n

}

consumer:

while (true) {

/* do nothing while no data */;

while (in == out){;}

w = Buff[out];

out = (out + 1) % n;

/* consume item w */

}

Note: shaded area indicates occupied locations

•Block:(i) Producer – insert in full buffer(ii) Consumer – remove from empty buffer

•Unblock:(i) Consumer – remove item (ii) Producer – insert item

Buff[3] Buff[4] Buff[5]

out in

Buff[1] Buff[2] ...Buff[0] Buff[n-1]

Buff[3] Buff[4] Buff[5]

in out

Buff[1] Buff[2] ...Buff[0] Buff[n-1]

Page 39: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Multiple producers, Multiple consumers, Finite buffer

• buff_space – semaphore that counts the free space from the buffer• product – semaphore that counts the produced items and not consumed yet• buff_access_prod is a semaphore that synchronizes the access of producers to the buffer• buff_access_cons is a semaphore that synchronizes the access of the consumers to the buffer

void producerX(){ while (TRUE){ produce_object(); wait (buff_space); wait(buff_access_prod); append(); signal(buff_access_prod); signal(product); something_else(); }}

main(){create_semaphore(product);create_semaphore(buff_access_prod);create_semaphore(buff_access_cons);create_semaphore(buff_space);/*initialize the buff_space semaphor to the size of the buffer*/

init_proc(&producer1(), …); init_proc(&producer2(), …); /*…*/init_proc(&producerN(), …); init_proc(&consumer1(), …);init_proc(&consumer2(), …);/*…*/init_proc(&consumerM(), …);}

void consumerY{ while (TRUE){ wait(product); wait(buff_access_cons); take(); signal(buff_access_cons); signal(buff_space); consume_object(); something else(); }}

Page 40: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores implementation

• As mentioned earlier, it is imperative that the wait and signal operations to be atomic primitives

• The essence of the problem is mutual exclusion– Only one process at a time may manipulate a semaphore with

either a wait or signal operation• Any of the software schemas would do (Peterson’s and Dekker’s

algorithms)

• Large amount of processing overhead

• The alternative is to use hardware supported schemas for mutual exclusion– Semaphores implemented with test&set instruction

– Semaphores implemented with disable/enable interrupts

Page 41: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores implementation with test&set

• The semaphore s is a structure, as explained earlier, but now includes a new integer component, s.flag

• This involves a form of busy waiting, but the primitives wait and signal are short, so the amount of waiting time involved should be minor

wait(s){ while (!testset(s.flag))/* do nothing */; s.count--; if (s.count < 0){ /*place this process in s.queue; block this process*/ } s.flag = 0;}

signal(s){ while (!testset(s.flag)){;} /*do nothing*/ s.count++; if (s.count <= 0){ /*remove a process P from s.queue; place process P on ready list*/ } s.flag = 0;}

Page 42: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphores implemented using interrupts

• For single processor system it is possible to inhibit the interrupts for the duration of a wait or signal operation

• The relative short duration of these operations means that this approach is reasonable

wait(s){ disable_interrupts(); s.count--; if (s.count < 0){ /*place this process in s.queue; block this process } enable_interrupts();}

signal(s){ disable_interrupts(); s.count++; if (s.count <= 0){ /*remove a process P from s.queue; place process P on ready list*/ } enable_interrupts();}

Page 43: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Inter Process Communication

• Inter process data exchange, execution state report, results collection is part of inter process communication; it can be done using some shared memory zones, therefore synchronization is required

• Semaphores are primitive (yet powerful) tools to enforce mutual exclusion and for process coordination; still, it may be difficult to produce a correct program using semaphores– The difficulty is caused by the fact that wait and signal

operations may be scattered throughout a program and is not easy to see an overall effect

Page 44: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Messages

• When a process interacts with another, two main fundamental requirements must be satisfied: communication and synchronization

• Message passing provides both of those functions• Message-passing systems come in many forms; this

section will provide a general view of typical features found in such systems

• The message-passing function is normally provided in the form of primitives:– Send (destination, message)

– Receive (source, message)

Page 45: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Messages design issues• Synchronization

– Blocking vs. Non-blocking• Addressing

– Direct– Indirect

• Message transmission– Through value– Through reference

• Format– Content– Length

• Fixed• Variable

• Queuing discipline– FIFO– Priority

Page 46: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Synchronization

• Send gets executed in a process– Sending process is blocked until the receiver gets the message

– Sending process continues its execution in a non blocking fashion

• Receive gets executed in a process– If a message has been previously sent, the message is received

and execution continues

– If there is no waiting message then• Process can be blocked until a message arrives

• The process continues to execute, abandoning the attempt to receive

• So both the sender and receiver can be blocking or not

Page 47: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Synchronization …

• There are three typical combinations of systems– Blocking send, blocking receive

• Both the receiver and sender are blocked until the message is delivered (provides tight sync between processes)

– Non-blocking send, blocking receive• The sender can continue the execution after sending a

message, the receiver is blocked until message arrives (it is probably the most useful combination)

– Non-blocking send, non-blocking receive• Neither party waits

• Typically only one or two combinations are implemented

Page 48: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Addressing• Direct addressing

– Send primitive include the identifier of the receiving process– Receive can be handled in two ways

• Receiving process explicitly designates the sending process (effective for cooperating processes)

• Receiving process is not specifying the sending process (known as implicit addressing); in this case, the source parameter of receive primitive has a value returned when the receive operation has been completed

• Indirect addressing– The messages are not sent directly from sender to receiver, but

rather they are sent to a shared data structure consisting of queues that temporarily can hold messages; those are referred to as mailboxes.

– Two communicating process:• One process sends a message to a mail box• Receiving process picks the message from the mailbox

Page 49: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Indirect process communication• Indirect addressing decuples the

sender form the receiver allowing for greater flexibility.

• Relationship between sender and receiver:– One to one

• Private communications link to be set up between two processes

– Many to one• Useful for client server interaction;

one process provides services to other processes; in this case, the mailbox is known as port

– One to many• Message or information is

broadcasted across a number of processes

– Many to many

Page 50: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Message transmission• Through value

– Require temp buffers in the operating system that would store the sent messages until the receiver would receive them

– Overloading of the OS

• Through reference– Doesn’t require temporary buffers– Faster than the value passing method– Requires protection of the shared memory– It is difficult to implement when the sender and receiver are located on

different machines

• Mixed passing– The sending is done through reference– If it is the case (the receiver tries to modify the received message), the

message gets transmitted again, this time through value

Page 51: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Message format• Fixed length

– Easy to implement– Minimizes the processing and

storage overhead– If large amount of data is to be

sent, that data is placed into a file and the file is referenced by the message

• Variable length– Message is divided in two parts:

header and body– Requires dynamic memory

allocation, so fragmentation could occur

Page 52: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Queuing discipline

• Simplest queuing discipline is first in first out

• Sometime it is not enough, since some messages may have higher priority then others– Allow the sender to specify the message priority, either

explicitly or based on some sort of message types– Allow the receiver to inspect the message queue and

select which message to receive next

Page 53: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Mutual exclusion using messages

• We assume the using of a blocking receive primitive and a non-blocking send primitive• mutex – is a shared mailbox, which can be used by all processes to send and receive• The mailbox is initialized to contain a single message with null content• A process wishing to enter its critical section, first attempts to receive a message; it will

be block if no message is in the mailbox; once has aquired the message, it performs its critical section and then places a message back into the mailbox

• The message functions as a token that is passed between process to process

/* program mutualexclusion */void Proc(int i){ message msg; while (true){ receive (mutex, msg); /* critical section */; send (mutex, msg); /* remainder */; }}

void main(){create_mailbox (mutex);/*initialize the mailbox with a null message*/send (mutex, null);

init_proc(&proc(1), …);init_proc(&proc(2), …);init_proc(&proc(3), …);/*…*/init_proc(&proc(N), …);}

Page 54: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Readers/Writers problems• There is a data area shared among a number of processes (i.e. file,

bank of main memory, etc..)• There are a number of processes that only read the data area

(readers) or write it (writers)• Conditions that must be satisfied:

– Any number of readers may simultaneously read the data– Only one writer at the time may write the data– If a writer is writing the data, no reader may read it

• Note that this problem is not the same as the producer/consumer problem, since the readers only read data and the writers only write data … the readers don’t modify the data structures nor the writers read the data structures (to find out where to write).

• Two solutions– Readers with priority– Writers with priority

Page 55: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Readers have priority

• readcount_sem – semaphore that synchronizes the access to the variable that keeps the number of parallel readers (readcount)

• write_sem – semaphore that controls the access of writers• As long as the writer is accessing the shared area, no other writers nor readers

may access it

void readerX(){ while (TRUE){ wait(readcount_sem); readcount++; if (readcount==1){ wait(write_sem); /*block the writers while read in progress*/ } signal(readcount_sem); READ_UNIT(); wait(readcount_sem); readcount--; if(readcount==0){ signal(write_sem); //unblock writers } signal(readcount_sem); }}

int readcount = 0;main(){create_semaphore(readcount_sem);create_semaphore(write_sem);/*initialize the semaphores to 1*/signal(readcount_sem);signal(write_sem);

init_proc(&reader1(), …); init_proc(&reader2(), …); /*…*/init_proc(&readerN(), …); init_proc(&writer1(), …);init_proc(&writer2(), …);/*…*/init_proc(&writerM(), …);}

void writerY{ while (TRUE){ wait(write_sem); WRITE_UNIT(); signal(write_sem); }}

Page 56: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

References

• “Operating Systems”, William Stallings, ISBN 0-13-032986-X

• “Operating Systems – A modern perspective”, Garry Nutt, ISBN 0-8053-1295-1

Page 57: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

• Additional slides

Page 58: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Linux Fork()• fork()

– returns 0 to child– return child_pid to parent

• Parent is responsible to look after children– Failure to do so can create zombies– pid = wait( &status ) to explicitly wait for the child

to terminate– signal(SIGCHLD, SIG_IGN) to ignore child-

termination signals– May also set SIGCHLD to call a specified

subroutine when a child dies

Page 59: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Fork() Example/* Example of use of fork system call */#include <stdio.h>

main(){ int pid; int var = 100; pid = fork();

if (pid < 0) { /* error occurred */ fprintf(stderr, "Fork failed!\n"); exit(-1);

} else if (pid==0) { /* child process */

var = 200; printf("I am the child, pid=%d\n", getpid()); printf("My child variable value is %d\n",var);

} else { /* parent process */

printf("I am the parent, pid=%d\n", getpid() ); printf("My parent variable value is %d\n",var); exit(0);

}}

Page 60: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

System V Semaphores• Generalization of wait and signal primitives

– Several operations can be done simultaneously and the increment and decrement operations can be values greater than 1

– The kernel does all the requested operations atomically

• Elements:– Current value of the semaphore– Process ID of last process that operates on the semaphore– Number of processes waiting for the semaphore value to be

greater than its current value– Number of processes waiting for the semaphore value to be

zero

• Associated with the semaphores are queues of processes suspended on that semaphore

Page 61: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

System V Semaphores• Key - 4 byte value for the “name”• Create/access semaphores (you can create them in sets)

– id = semget( KEY, Count, IPC_CREAT | PERM )– id = semget( KEY, 0, 0 )

• Perm = file permission bits (0666)• to create only (fails if exists) use IPC_CREAT|

IPC_EXCL|PERM• Count = # of semaphores to create

• Controlling semaphores– i = semctl( id, num, cmd, … )

• id – identifier of the semaphore set• num – number of the semaphore to be processed• cmd – type of command (GETVAL, SETVAL, GETPID

… )• … - up to the type of command• i.e. - deleting semaphores

– i = semctl( id, 0, IPC_RMID, 0 )

Page 62: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphore Operations (System V)• Operations on semaphores

– semop(id, sembuf *sops, nsops)• id – identifier of the semaphore set• sops – points to the user defined array of sembuf structures that contain the

semaphore operations• nsops – The number of sembuf structures in the array

– Semaphore Structurestruct sembuf {

short sem_num; (semaphore ID)short sem_op; (change amount)short sem_flg; (wait/don’t wait)} op;

– sem_flg can be 0 or IPC_NOWAIT• Wait():

– op.sem_op = -1 (decrement)– res = semop( id, &op, 1 )

• Signal():– op.sem_op = 1 (increment)– res = semop( id, &op, 1 )

Page 63: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Linux Semaphore (Posix)

• int sem_init(sem_t *sem, int pshared, unsigned int value)

• int sem_wait(sem_t *sem)

• int sem_post(sem_t *sem)

• int sem_getvalue(sem_t *sem, int *val)

• int sem_destroy(sem_t *sem)

Page 64: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared Memory

• Fastest way of inter process communication• It is a common block of virtual memory shared by

multiple processes• Read and write of the shared memory is done

using same read and write for normal memory• Permissions (read only or read/write) are

determined per process basis• Mutual exclusion constrains are not provided by

the shared memory, but they have to be programmed in the processes that are using it

Page 65: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared Memory• Create/Access Shared Memory

– id = shmget( KEY, Size, IPC_CREAT | PERM )– id = shmget( KEY, 0, 0 )

• Deleting Shared Memory– i = shmctl( id, IPC_RMID, 0 )– Or use ipcrm

• Accessing Shared Memory– memaddr = shmat( id, 0, 0 )– memaddr = shmat( id, addr, 0 )

• Addr should be multiple of SHMLBA– memaddr = shmat( id, 0, SHM_READONLY )

• System will decide address to place the memory at

– shmdt( memaddr )• Detach from shared memory

Page 66: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Unix Pipes

• Circular buffer allowing processes to communicate to each other following producer-consumer model– It is a first in first out queue, written by one process and read by

another

• When a pipe is created is given a fixed size in bytes– When a process attempts to write into the pipe, the write

request is immediately executed if there is enough room; otherwise, the process is blocked

– Similarly, a read process is blocked if attempts to read more than it is in the pipe

Page 67: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Unix Pipes• Creates a one-way connection between processes• Created using pipe() call

– Returns a pair of file descriptors• pend[0] = read end• pend[1] = write end

– Use dup() call to convert to stdin/stdout• Example:

int pend[2]pipe( pend )fork()parent childclose(pend[1]) close(pend[0]) write(pend[1],…)read(pend[0],…)close(pend[0]) close(pend[1])

Page 68: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Unix Messages• Send information (type + data) between processes• Message Structure

– long type– char text[]

• Functions:– Create/access

• id = msgget( KEY, IPC_CREAT|IPC_EXCL…)• id = msgget( KEY, 0 )

– Control• msgctl( id, IPC_RMID )

– Send/receive• msgsnd( id, buf, text_size, flags )• msgrcv( id, buf, max_size, flags )

– Useful Flags• IPC_NOWAIT• MSG_NOERROR (truncate long messages to max_size)

Page 69: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Semaphore example#include <errno.h>#include <pthread.h> /* Posix Threads */#include <semaphore.h> /* Posix Semaphores */#include <stdarg.h>#include <stdio.h>

sem_t s;/* takes free format error message much like printf, exits unconditionally */void errprint(const char *fmt, ...){ va_list args; va_start(args,fmt); vfprintf(stderr, fmt, args); va_end(args); exit(1);}

void * MyThread(void * arg){ int i; printf("Entering MyThread\n"); for (i = 0; i < 10; ++i){ sem_wait(&s); printf("MyThread gets access to critical section\n"); fflush(stdout); /*some critical section code here*/ sleep(2); sem_post(&s); } pthread_exit( (void *) 0); return (void *) NULL;}

int main(){ int i; /* iteration variable */ int status; /* return status of calls */ pthread_t tid; /* Thread id */

/* Semaphore initialization */ sem_init(&s, /* the semaphore */ 0, /* is the semaphore shared or not? (on Linux only non shared sems are supported) */ 1); /* Initial semaphore value */ /* Create and run the threads */ status = pthread_create(&tid, NULL, MyThread, (void *) NULL); if (status != 0){

errprint("MyThread creation failed with %d, errno = %d\n", status, errno, strerror(errno));

} /* Main continues execution, main is its own thread */ for (i = 0; i < 15; ++i){ sem_wait(&s); printf("Main gets access to critical section\n");

/* some critical sectin code */ sleep(1);

sem_post(&s); } /* Wait for Thread Termination */ pthread_join(tid, NULL); if (status != 0){ errprint("Thread join of MyTread failed with %d, errno = %d\n",

status, errno, strerror(errno)); }}

Page 70: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared memory server/*--------------------------------------+| UNIX header files |+--------------------------------------*/#include <sys/types.h>#include <unistd.h>#include <fcntl.h>#include <sys/ipc.h>#include <sys/stat.h>#include <sys/shm.h>/*--------------------------------------+| ISO/ANSI header files |+--------------------------------------*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <time.h>#include <errno.h>/*--------------------------------------+| Constants |+--------------------------------------*//* value to fill memory segment */#define MEM_CHK_CHAR '*' /* shared memory key */#define SHM_KEY (key_t)1097 /* size of memory segment (bytes) */#define SHM_SIZE (size_t)256 /* give everyone read/write permission *//* to shared memory */#define SHM_PERM (S_IRUSR|\S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)

/*----------------------------------------+| Name: main || Returns: exit(EXIT_SUCCESS) or || exit(EXIT_FAILURE) |+-----------------------------------------*/int main(){/* shared memory segment id */ int shMemSegID; /* shared memory flags */ int shmFlags; /* ptr to shared memory segment */ char * shMemSeg; /*---------------------------------------*//* Create shared memory segment *//* Give everyone read/write permissions. *//*---------------------------------------*/ shmFlags = IPC_CREAT | SHM_PERM; if ( (shMemSegID = shmget(SHM_KEY, SHM_SIZE, shmFlags)) < 0 ){ perror("SERVER: shmget"); exit(EXIT_FAILURE); }/*-------------------------------------------*//* Attach the segment to the process's data *//* space at an address *//* selected by the system. *//*-------------------------------------------*/shmFlags = 0;if ( (shMemSeg = shmat(shMemSegID, NULL, shmFlags)) == (void *) -1 ){ perror("SERVER: shmat"); exit(EXIT_FAILURE);}

Page 71: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared memory server/*-------------------------------------------*//* Fill the memory segment with MEM_CHK_CHAR *//* for other processes to read *//*-------------------------------------------*/memset(shMemSeg, MEM_CHK_CHAR, SHM_SIZE);/*-----------------------------------------------*//* Go to sleep until some other process changes *//* first character *//* in the shared memory segment. *//*-----------------------------------------------*/while (*shMemSeg == MEM_CHK_CHAR){

sleep(1);}

/*------------------------------------------------*//* Call shmdt() to detach shared memory segment. *//*------------------------------------------------*/if ( shmdt(shMemSeg) < 0 ){ perror("SERVER: shmdt"); exit(EXIT_FAILURE);}/*--------------------------------------------------*//* Call shmctl to remove shared memory segment. *//*--------------------------------------------------*/ if (shmctl(shMemSegID, IPC_RMID, NULL) < 0){ perror("SERVER: shmctl"); exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);} /* end of main() */

Page 72: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared memory client/*-------------------------------------+| UNIX header files |+-------------------------------------*/#include <sys/types.h>#include <sys/stat.h>#include <sys/ipc.h>#include <sys/shm.h>/*-------------------------------------+| ISO/ANSI header files |+-------------------------------------*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>/*-------------------------------------+| Constants |+-------------------------------------*//* memory segment character value */#define MEM_CHK_CHAR '*' /* shared memory key */#define SHM_KEY (key_t)1097 #define SHM_SIZE (size_t)256 /* size of memory segment (bytes) *//* give everyone read/write *//* permission to shared memory */#define SHM_PERM (S_IRUSR|S_IWUSR|\S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)

/*------------------------------------+| Name: main || Returns: exit(EXIT_SUCCESS) or || exit(EXIT_FAILURE) |+------------------------------------*/

int main(){/* loop counter */ int i; /* shared memory segment id */ int shMemSegID; /* shared memory flags */ int shmFlags; /* ptr to shared memory segment */ char * shMemSeg; /* generic char pointer */ char * cptr; /*-------------------------------------*//* Get the shared memory segment for *//* SHM_KEY, which was set by *//* the shared memory server. *//*-------------------------------------*/ shmFlags = SHM_PERM;if ( (shMemSegID = shmget(SHM_KEY, SHM_SIZE, shmFlags)) < 0 ){ perror("CLIENT: shmget"); exit(EXIT_FAILURE);}

Page 73: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Shared memory client/*-----------------------------------------*//* Attach the segment to the process's *//* data space at an address *//* selected by the system. *//*-----------------------------------------*/shmFlags = 0;if ( (shMemSeg = shmat(shMemSegID, NULL, shmFlags)) == (void *) -1 ){ perror("SERVER: shmat"); exit(EXIT_FAILURE);}/*-------------------------------------------*//* Read the memory segment and verify that *//* it contains the values *//* MEM_CHK_CHAR and print them to the screen *//*-------------------------------------------*/for (i=0, cptr = shMemSeg; i < SHM_SIZE; i++, cptr++){ if ( *cptr != MEM_CHK_CHAR ){ fprintf(stderr, "CLIENT: Memory Segment corrupted!\n"); exit(EXIT_FAILURE); }putchar( *cptr );/* print 40 columns across */ if ( ((i+1) % 40) == 0 ){ putchar('\n'); }}putchar('\n');

/*--------------------------------------------*//* Clear shared memory segment. *//*--------------------------------------------*/ memset(shMemSeg, '\0', SHM_SIZE);

/*------------------------------------------*//* Call shmdt() to detach shared *//* memory segment. *//*------------------------------------------*/if ( shmdt(shMemSeg) < 0 ){ perror("SERVER: shmdt"); exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);} /* end of main() */

Page 74: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Pipe example

#include <errno.h>#include <stdio.h>#include <unistd.h>

void error(char *mesg){ fprintf(stderr, "Error <%s> errno = %d", mesg, errno); perror(mesg); exit(1);}

int main(){ char buffer[80]; int pfid[2]; /* the pipe file descriptors */ int status; status = pipe(pfid); if (status == -1){ error("Bad pipe call"); } status = fork(); /* create 2 processes */ if (status == -1){ error("Bad fork call"); } else if (status == 0){ /*child process*/ status = read(pfid[0], buffer, sizeof(buffer)); if (status != sizeof(buffer)){ error("Bad read from pipe"); } printf("Child pid = %d received the message <%s>\n", getpid(), buffer); status = close(pfid[0]); /* close the reader end */ } else { /*parent process*/ sprintf(buffer, "Pid of the Parent is <%d>", getpid()); status = write(pfid[1], buffer, sizeof(buffer)); if (status != sizeof(buffer)){ error("Bad write to pipe"); } status = close(pfid[1]); /* close the writer end */ }}

Page 75: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Unix messages example/* testmsg.c - uses the messages in Unix */#include <errno.h>#include <stdio.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>

void error(char *mesg){ fprintf(stderr, "Error <%s> errno = %d", mesg, errno); perror(mesg); exit(1);}void show_usage(char *mesg, char *prog_name){ fprintf(stderr, "Error <%s>\n", mesg); fprintf(stderr, "Usage is\n\t%s [\"-r\" | \"-w\"]\n\t"

" r for reader, w for writer\n", prog_name);}/* read in up to n bytes from stdin into buf */void read_buffer( char *buf, int n){ int c, done = 0, i; for (i = 0; !done && i < n && !feof(stdin) && !ferror(stdin); ++i){

c = getchar();if (c != EOF){ buf[i] = (char) c; done = buf[i] == '\n'; /* newline? */}

}

if (ferror(stdin)){perror("Bad read from stdin");

} else {

buf[i - 1] = '\0'; /* use ASCII NULL terminator */ }}

int main(int argc, char *argv[]){ key_t k; int msgqid; int status; struct {

long mtype; /* what message type ? */struct{ long pid; /* process id of sender */ char str[80]; /* some string to send */} data;

} msg_rec; /* get the key of the message queue */ k = ftok(argv[0], 0);

printf ("Key Value is %d\n", k); if (argc != 2){

show_usage("Wrong Number of Parameters", argv[0]);exit(1);

}

Page 76: Inter Process Synchronization and Communication CT213 – Computing Systems Organization

Unix message exampleelse if (!strcmp(argv[1],"-r")){ msgqid = msgget(k, S_IRUSR); /* Open read only, not creating so ignore perms */ if (msgqid < 0){ printf("Error creating the message\n"); fprintf(stderr, "Bad msgget %ld for read\n", (long) k); error("Bad msgget create and read perms"); } status = msgrcv( msgqid, /* which msg queue */

(void *) &msg_rec, /* data to recv */sizeof(msg_rec.data),0, /* Message Type 0 = wild card */0); /* Flags (Blocking) */

/* if msg type is > 0 then looks for exact match, if msg type < 0 then will take the first message satisfying -(msg.type) >= incoming_msg.type */if (status < 0){ perror("Bad msgrcv");}printf("Received Message data.pid = %ld, str=<%s>\n", msg_rec.data.pid, msg_rec.data.str);}

else if (!strcmp(argv[1],"-w")){ /* Create a message queue with owner level read/write permissions */ msgqid = msgget(k, IPC_CREAT|S_IWUSR|S_IRUSR); /*test to see if the message queue has been succesfully created*/ if (msgqid < 0){ fprintf(stderr, "Bad msgget %ld create for

read and write\n", (long) k); error("Bad msgget create, read and write"); } /*initialize the message type*/ msg_rec.mtype = 99; /* encode the pid in the msg */ msg_rec.data.pid = getpid(); printf("Enter your message here>"); flush(stdout); /* user inputs the string to send */ read_buffer(msg_rec.data.str, sizeof(msg_rec.data.str)); status = msgsnd( msgqid, /* which msg queue */

(void *) &msg_rec, /* data to send */ sizeof(msg_rec.data), /* how much data to send */ 0); /* Flags (Blocking Send) */

if (status < 0){ error("Bad msgsnd"); } /* remove the msg queue */ status = msgctl( msgqid, IPC_RMID, 0); if (status < 0){ error("Bad remove of message queue"); }}}