3. Message QUEUE

advertisement
Unit V
Inter process communication
Introduction
1. Pipes
2. FIFOs
System V IPC
3. Message Queues
4 .Semaphores
5. Shared Memory
What is IPC?
 Sharing of information between processes.
 IPC is a mechanism to transfer data between processes
Why IPC?




To share resources
For client/server applications
For modularity
For convenience
In unix we have three ways to share the information between processes
P1
P2
1
P3
P4
2
P5
Shared memory
P6
3
Shared information
Filesystem
1)
 Two processes p1 and p2 sharing some information that resides in a file in
filesystem.
 To access this data each process must go through the kernel (read, write).
2)
 Two process p3 and p4 are sharing information that resides with in the
kernel.
 Each operation to access the shared information involves a system call to the
kernel
 Ex:pipe,message queue, semaphores
3).
 Two process p5 and p6 have a region of shared memory that each process
can reference.
 Once shared memory is set up by the each process, then the process can
access the data in the shared memory without involving the kernel.
We can implement the IPC using five techniques
1. Pipes
2. FIFOs
3. Message Queue
4. Shared Memory
5. Semaphores
1. Pipes:
 Pipes are the oldest form of unix ipc and are provided by all unix systems.
 Pipes are used to share the information between parent and child process.
Parent process
pipe
(write)
child process
(read)
Figure 1.1
Pipes have two limitations:
1. Pipes are half duplex (i.e data flows in only one direction).
2. Pipes can be used only between processes that have a common ancestor.
Normally a pipe is created by a process, that process calls fork, and the pipe is used
between the parent and the child.
1.1 Creation of pipe:
pipe () function:
 pipe() function is used to create a pipe between parent and child.
Syntax:
# include<unistd.h>
int pipe (int filedes [2]);
Returns:0 if ok,
-1 on error

Two file descriptors are returned through the filedes argument.
file des[0] is open for reading
file des [1] is open for writing
 The output of filedes [1] is the input for filedes [0].
Two ways to view a half-duplex pipe
user process
fd[0]
user process
fd[0]
fd[1]
Figure 1.2
fd[1]
pipe
kernel
Figure1.3
 Figure 1 shows the two ends of the pipe connected in a single process.
 Figure 2 shows that the data in the pipe flows through the kernel.
 An IPC channel is created between parent and child when the parent process
calls pipe and then calls fork
Pipe from parent to child:
Parent
child
.
fd[1]
fd[0]
pipe
Kernel
Figure 1.4
For a pipe from the parent to child , the parent closes the read end of the
pipe(fd[0]) and the child closes the write end (fd[1]).
Pipe from child to parent:
Parent
child
.
fd[0]
fd[1]
pipe
Kernel
Figure 1.5
 For a pipe from the child to parent, the parent closes fd[1] and the child
closes the fd[0].
Ex: Write a c program to provide IPC using pipes?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
int main()
{
char str[20];
pid_t pid;
int fd[2],n;
pipe(fd);
pid=fork();
if(pid>0)
{
close(fd[0]);
write(fd[1],"IPC using pipes",14);
}
else
{
close(fd[1]);
n=read(fd[0],str,2);
write(STDOUT_FILENO,str,n);
}
}
Drawbacks of pipes:
 Pipes are used only between related processes. When a common ancestor
has created the pipe.
 Pipes are not permanent, a process creates the pipe and the termination of
that process leads to their destruction.
2. FIFOs





FIFOs are also called named pipes.
By using FIFOs, unrelated processes also exchange the data.
FIFOs are permanent.
FIFO is a file.
Creating a FIFO is similar to creating a file.
2.1 Creation of FIFO:
mkfifo() function:
 mkfifo function is used to create a new FIFO.
Syntax:
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
Returns:0 if OK ,
-1 on error




Here pathname is the name of FIFO
Specification of the mode is same as open() function.
Open() function is used to open an existing FIFO.
Normal I/O functions all work with FIFOs.
2.2 Uses of FIFOs:
 FIFOs are used by shell commands to pass data from one shell pipeline to
another without creating intermediate temporary files.
 FIFOs are used in client-server applications to pass data between thye clients
and the servers.
2.2.1 Example Using FIFOs to Duplicate Output Streams
 FIFOs can be used to duplicate an output stream in a series of shell
commands. This prevents writing the data to an intermediate disk file
(similar to using pipes to avoid intermediate disk files).
 But whereas pipes can be used only for linear connections between
processes, a FIFO has a name, so it can be used for nonlinear connections.
Consider a procedure that needs to process a filtered input stream twice.
Figure 2.1 shows this arrangement.
With a FIFO and the UNIX program tee we can accomplish this procedure without
using a temporary file. (The tee program copies its standard input to both its
standard output and to the file named on its command line.)
mkfifo fifo1
prog3 < fifo1 &
prog1 < infile | tee fifo1 | prog2
We create the FIFO and then start prog3, reading from the FIFO. We then start
Prog1 and use tee to send its input to both the FIFO and prog2. Figure 2 shows the
process arrangement.
Procedure that processes a filtered input stream twice
Prog3
input file
Prog1
Prog2
Figure 2.2.1
Using a FIFO and tee to send a stream to two different processes
FIFO
input file
Prog1
Prog3
tee
Prog2
Figure 2.2
2.2.2 Example Client-Server Communication Using a FIFO
 Here FIFOs are used to send data between a client and a server.
 If we have a server that is contacted by numerous clients, each client can
write its request to a well-known FIFO.
 Well-known FIFO is created by server.
 Well-known FIFO means that the pathname of the FIFO is known to all the
clients that need to contact the server.
Server
read request
Well-known
FIFo
Write request
write request
client
client
Figure 2.2.2.1
 In this each client writes the request into a well-known FIFO.
 Server reads the each client request from the well-known FIFO.
Problem:
 The problem in using FIFOs for this type of client-server communication is
how to send replies back from the server to each client.
 A single FIFO can't be used, as the clients would never know when to read
their response versus responses for other clients.
Solution:
 One solution is for each client to send its process ID with the request.
 The server then creates a unique FIFO for each client, using a pathname
based on the client's process ID
Server
read request
write replies
write replies
Client-specific
FIFO
read replies
Well-known
FIFO
write request
Client-specific
FIFO
write requests
client
client
figure 2.2.2.2
read replies
System V IPC:
 Message queue, shared memory and semaphores are called System V IPC
because these three have many similarities.
Identifiers and Keys
 Each IPC structure (message queue, semaphore, or shared memory segment)
in the kernel is referred to by a non-negative integer identifier.
 To send or fetch a message to or from a message queue, we need the
identifier for the queue.
 The identifier is an internal name for an IPC object.
Permission Structure
 Each System V IPC techniques having the following permission structure.
struct ipc_perm {
uid_t uid; /* owner's effective user id */
gid_t gid; /* owner's effective group id */
uid_t cuid; /* creator's effective user id */
gid_t cgid; /* creator's effective group id */
mode_t mode; /* access modes */
.
.
.
};
Configuration Limits
 All three forms of System V IPC have built-in limits that we may
encounter. Most of these limits can be changed by reconfiguring the kernel
Advantages and Disadvantages
 A fundamental problem with System V IPC is that the IPC structures are
system wide and do not have a reference count. For example, if we create a
message queue, place some messages on the queue, and then terminate, the
message queue and its contents are not deleted. They remain in the system
until specifically read or deleted by some process calling msgrcv or msgctl.
 Another problem with XSI IPC is that these IPC structures are not known by
names in the file system.
3. Message QUEUE:





Queue is a data structure
Message is a small group of data
Messages are passed between processes through a message queue.
Message queue is a queue on to which the messages are placed.
A message queue is a linked list of messages stored within the kernel and
identified by a message queue identifier.
 Message with in a queue are of different types.
Data structures related to Message queue:
Struct msqid_ds
{
struct ipc_perm msg_perm;
struct msg *msg_first; /*Pointer to 1st msg on queue*/
struct msg *msg_last; /*Pointer to last msg on queue*/
ulong msg_cbytes;/*current number of bytes on queue*/
ulong msg_qnum;/* number of messages on queue*/
ulong msg_qbytes;/*max number of bytes on queue*/
pid_t msg_lspid;/*pid of last msgsnd()*/
pid_t msg_lrpid;/*pid of last msgrcv()*/
time_t stime;/*last msgsnd()*/
time_t rtime;/*last msgrcv()*/
time_t ctime;/*last change time*/
.}
3.1 Creating a message queue:
msgget()function:
 used to create a new message queue or to open an existing message
queue.
Syntax:
#include <sys/msg.h>
int msgget(key_t key, int flag);
Returns: message queue ID if OK,
1 on error
In either of the following cases a new IPC structure is created.
 key is IPC-PRIVATE
 flag is IPC-CREAT
When a new queue is created the following members of the msqid_ds structure are
initialized
 ipc-perm structure is initialized
 msg_qnum, msg_lspid, msg_lrpid, msg_stime, and msg_rtime are all set to
0.
 msg_ctime is set to the current time.
 msg_qbytes is set to the system limit.
 On success, msgget returns the non-negative queue ID.
Eg:
/*Program to create a message queue*/
#include<sys/types.h>
#include<sys/msg.h>
#include<sys/ipc.h>
int main()
{
key-t key=100;
Int msqid;
msqid=msgget(key,IPC-CREAT/0666);
pf(“message queue id is%d”,msqid);
}
Message queue structure in the kernel:
Ipc_perm[]
NULL
NULL
NULL
Msg_first
type
type
type
Msg_last
length
length
length
.
data
data
data
.
.
Msg.ctime
Figure 3.1
3.2 Write/send a message into a message queue:
msg snd()function:
 This function is used to place data on a message queue.
 Data is placed onto a message queue by calling msgsnd.
Syntax:
#include <sys/msg.h>
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
Returns: 0 if OK,
1 on error
 Ptr argument is the pointer to a message structure.
 Messages are placed at the end of the queue
 When msgsnd()returns successfully, then msqid_ds structure associated
with the message queue is updated.
struct message
{
long m type,/*message type*/
char mtext[512],/*message data*/
};
3.3 Fetch/Receive a message from message queue:
msgrcv() function:
 This function is used to retrieve data from a message queue
 Messages are retrieved from a queue by msgrcv.
Syntax:
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes , long type, int flag);
Returns: size of data portion of message if OK,
1 on error
 Ptr argument points to a message structure.
 N bytes specify the size of the data
 The type argument lets us specify which message we want.
type == 0 The first message on the queue is returned.
type > 0
The first message on the queue whose message type equals
type is returned.
type < 0
The first message on the queue whose message type is the
lowest value less than or equal to the absolute
value of type is returned.
 We can specify the flag value as IPC_NOWAIT to make the operation
non-blocking.
3.4 msgctl() function:
 The msgctl function performs various operations on a queue
 Used to know the status of a message queue and to delete a message
queue from the system.
Syntax:
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf );
Returns: 0 if OK,
1 on error
The cmd argument specifies the command to be performed on the queue specified
by msqid.
IPC_STAT
Fetch the msqid_ds structure for this queue, storing it in the
structure pointed to by buf.
IPC_SET
Copy the following fields from the structure pointed to by buf to
the msqid_ds structure associated with this queue:
msg_perm.uid,msg_perm.gid,msg_perm.mode, and
msg_qbytes. msg_perm.cuid or msg_perm.uid
IPC_RMID
Remove the message queue from the system and any data still
on the queue. This removal is immediate. Any other process
using the message queue will get an error .
a) Write a ‘c’ program to create a message queue and send a message into the
queue.
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
struct mesg
{
long type;
char mtext[252];
} mesg;
main ()
{
int msqid,len;
if((msqid=msgget((key_t)10,IPC_CREAT|0666))<0)
{
printf("not");
}
printf("qid is=%d",msqid);
mesg.type=6;
strcpy(mesg.mtext,"example for mq");
len=strlen(mesg.mtext);
if(msgsnd(msqid,&mesg,len,0)==-1)
printf("write error");
printf("data is placed successfully");
}
O/P: mesg que id is =0.
Data is placed into the queue=example of mq.
b) Read the message in the message queue written in the previous program.
#include<stdio.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<sys/types.h>
struct mesg
{
long type;
char mtext[255];
}mesg;
main()
{
int msqid;
if((msqid=msgget((key_t)10,IPC_CREAT|0666))<0)
printf("error");
printf("received mq id is=%d",msqid);
if((msgrcv(msqid,&mesg,255,6,IPC_NOWAIT))<0)
printf("ERRROR");
printf("%s",mesg.mtext);
}
4. Shared memory
 Shared memory is region of memory that is shared by two or more
processes.
 Shared memory allows two or more processes to share a given region of
memory.
 This is the fastest form of IPC, because the data does not need to be copied
between the client and the server.
 The only trick in using shared memory is synchronizing access to a given
region among multiple processes.
 If the server is placing data into a shared memory region, the client shouldn't
try to access the data until the server is done.
 Often, semaphores are used to synchronize shared memory access.
Address space for process A
Address space for
Physical memory
Shared
memory region
Figure 4.1
Process B
Data structures for Shared memory:
 The kernel maintains a structure for each shared memory segment
struct shmid_ds {
struct ipc_perm shm_perm;
size_t
shm_segsz; /* size of segment in bytes */
pid_t
shm_lpid; /* pid of last shmop () */
pid_t
shm_cpid; /* pid of creator */
shmatt_t
shm_nattch; /* number of current attaches */
time_t
shm_atime; /* last-attach time */
time_t
shm_dtime; /* last-detach time */
time_t
shm_ctime; /* last-change time */
.
.
.
};
4.1Creation of shared memory segment:
shmget() function:
 This function is used to create or obtain a shared memory segment.
Syntax:
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
Returns: shared memory ID if OK, 1 on error
 Key is the address of shared memory segment.
When a new segment is created, the following members of the shmid_ds
structure are initialized.
The ipc_perm structure is initialized
 shm_lpid, shm_nattach, shm_atime, and shm_dtime are all set to 0.
 shm_ctime is set to the current time.
 shm_segsz is set to the size requested.
 The size parameter is the size of the shared memory segment in bytes
4.2 Attaching a shared memory segment to the process address
space:
shmat() function
 This function is used to attach a shared memory segment to a process
address space.
 Once a shared memory segment has been created, a process attaches it to its
address space by calling shmat.
Syntax:
#include <sys/shm.h>
void *shmat(int shmid, const void *addr, int flag);
Returns: pointer to shared memory segment if OK, 1 on error
Based on addr value shared memory segment is attach to process address space
 If addr is 0, the segment is attached at the first available address selected by
the kernel. This is the recommended technique.
 If addr is nonzero and SHM_RND is not specified, the segment is attached
at the address given by addr.
 If addr is nonzero and SHM_RND is specified, the segment is attached at the
address given by addr
4.3 Detaching shared memory segment from the process address
space:
shmdt() function
 This function is used to detach a shared memory segment from a process
address space
Syntax:
#include <sys/shm.h>
int shmdt(void *addr);
Returns: 0 if OK,
1 on error
The addr argument is the value that was returned by a previous call to shmat. If
successful, shmdt will decrement the shm_nattch counter in the associated hmid_ds
structure.
shmctl() function:
 The shmctl function is the catchall for various shared memory operations.
 This function is used to remove a shared memory segment from a system
and also used to know the status of a shared memory segment
Syntax :
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
Returns: 0 if OK, 1 on error
The cmd argument specifies one of the following commands to be performed, on
the segment specified by shmid.
If cmd= IPC_STAT Fetch the shmid_ds structure for this segment, storing it
in the structure pointed to by buf
if cmd=IPC_RMID Remove the shared memory segment set from the system.
if cmd=IPC_SET Set the following three fields from the structure pointed to
by buf in the shmid_ds structure associated with this shared
memory segment: shm_perm.uid,shm_perm.gid, and
shm_perm.mode
Ex: Write a c program that illustrates the inter process communication using shared
memory
Process A:
#include<stdio.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<string.h>
main()
{
int shmid,flag;
key_t key=0x1000;
char *msg;
shmid=shmget(key,10,IPC_CREAT|0666);
if(shmid<0)
{
printf("error");
}
printf("%d\n",shmid);
msg=shmat(shmid,0,0);
//printf("%u",msg);
strcpy(msg,"example for sharedmemory");
//printf("%s",msg);
//write(1,msg,strlen(msg));
}
Process B
#include<stdio.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<sys/ipc.h>
main()
{
int shmid;
key_t key=0x1000;
char *msg;
shmid=shmget(key,10,IPC_CREAT|0666);
if(shmid<0)
{
printf("error");
}
printf("id is%d",shmid);
msg=shmat(shmid,0,0);
//read(shmid,msg,strlen(msg));
printf("%s",msg);
}
5. Semaphores:
 A semaphore is not a form of IPC similar to the pipes, FIFOs, and
message queues.
 A semaphore is a counter used to provide access to a shared data object for
multiple processes.
 Semaphore is an integer.
 Semaphore is used to control shared resource.
 Semaphore is a synchronization tool.
5.1 Types of semaphores
Binary semaphore: It controls a single resource, and its value is initialized to 1. In
general If the semaphore value is zero means resource is in use. .If the semaphore
value is one means resource is available.
Counting semaphore: a semaphore whose value is between zero or and some
limit. A semaphore can be initialized to any positive value, with the value
indicating how many units of the shared resource are available for sharing
To obtain a shared resource, a process needs to do the following:
1. Test the semaphore that controls the resource.
2. If the value of the semaphore is positive, the process can use the resource. In this
case, the process decrements the semaphore value by 1, indicating that it has used
one unit of the resource.
3.If the value of the semaphore is 0, the process goes to sleep until the semaphore
value is greater than 0. When the process wakes up, it returns to step 1.
4. When a process is done with a shared resource that is controlled by a semaphore,
the semaphore value is incremented by 1. If any other processes are asleep, waiting
for the semaphore, they are awakened.
Data structures for semaphore:
The kernel maintains a semid_ds structure for each semaphore set:
Struct semid_ds {
struct ipc_perm sem_perm;
unsigned short sem_nsems; /* # of semaphores in set */
time_t sem_otime; /* last-semop() time */
time_t sem_ctime; /* last-change time */
.
.
.
};
Each semaphore is represented by an anonymous structure containing at least the
following members:
struct {
unsigned short semval; /* semaphore value, always >= 0 */
pid_t sempid; /* pid for last operation */
unsigned short semncnt; /* # processes awaiting semval>curval */
unsigned short semzcnt; /* # processes awaiting semval==0 */
.
.
.
};
5.2 Creation of semaphore:
semget() function
 This function is used to create a new semaphore or obtain a semaphore ID.
Syntax:
#include <sys/sem.h>
int semget(key_t key, int nsems, int flag);
Returns: semaphore ID if OK, 1 on error
When a new set is created, the following members of the semid_ds structure are
initialized.
 The ipc_perm structure is initialized
 sem_otime is set to 0.
 sem_ctime is set to the current time.
 sem_nsems is set to nsems.
The number of semaphores in the set is nsems. If a new set is being created
(typically in the server),we must specify nsems. If we are referencing an existing
set (a client), we can specify nsems as 0.
Ex:Write a c program to create a new semaphore?
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
int semid;
key=(key_t)0x20;
semid=semget(key,1,IPC_creat|0666);
printf(“semid=%d”,semid);
}
5.3 Operations on semaphore:
semop() function
 The function semop atomically performs an array of operations on a
semaphore set.

Syntax:
#include <sys/sem.h>
int semop(int semid, struct sembuf semoparray[],size_t nops);
Returns: 0 if OK,
1 on error
The semoparray argument is a pointer to an array of semaphore operations,
represented by sembuf structures:
struct sembuf {
unsigned short sem_num; /* member # in set (0, 1, ..., nsems-1) */
short sem_op; /* operation (negative, 0, or positive) */
short sem_flg; /* IPC_NOWAIT, SEM_UNDO */
};
The nops argument specifies the number of operations (elements) in the array.
The operation on each member of the set is specified by the corresponding sem_op
value. This value can be negative, 0, or positive
5.4 semctl function
 The semctl function is the catchall for various semaphore operations.
 This function is used for the following
1 .To remove the semaphore set from the system.
2. To know the status of semaphore set.
3. To set the values to semaphore.
4. To get the semaphore values.
Syntax :
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd,
... /* union semun arg */);
The cmd argument specifies one of the following ten commands to be performed
on the set specified by semid.
IPC_STAT
Fetch the semid_ds structure for this set, storing it in the structure
pointed to by arg.buf.
IPC_SET
Set the sem_perm.uid, sem_perm.gid, and sem_perm.mode fields
from the structure pointed to by arg.buf in the semid_ds structure
associated with this set.
IPC_RMID
Remove the semaphore set from the system. Whose effective user
ID
equals sem_perm.cuid or sem_perm.uid
GETVAL
Return the value of semval for the member semnum.
SETVAL
Set the value of semval for the member semnum. The value is
specified by arg.val.
GETPID
Return the value of sempid for the member semnum.
GETNCNT Return the value of semncnt for the member semnum.
GETZCNT Return the value of semzcnt for the member semnum.
GETALL
Fetch all the semaphore values in the set. These values are stored in
the
array pointed to by arg.array.
SETALL
Set all the semaphore values in the set to the values pointed to by
arg.array.
Download