Linux Inter-process communication mechanism

Source: Internet
Author: User
Tags int size message queue new set random seed semaphore

Detailed narration of interprocess communication is absolutely impossible here, and the author is very difficult to be confident that the understanding of this part of the content to achieve what the point, so at the beginning of this section to recommend to you the famous author Richard Stevens's famous works: "Advanced Programming in the UNIX environment, its Chinese version of theadvanced programming of the UNIX environment has been published by the mechanical industry Press, the original text is wonderful, the translation is equally authentic, if you really have a strong interest in programming Linux, Then quickly put this book on your desk or next to the computer.    To say so much is really difficult to suppress the admiration of the heart, to the next, in this section, we will introduce the most preliminary and most simple communication between the knowledge and concepts. First, interprocess communication can be implemented at least through the transfer of open files, where different processes pass information through one or more files, and in fact, in many applications, this approach is used. In general, however, interprocess communication (ipc:interprocess communication) does not include this seemingly low-level communication method. There are many ways to implement interprocess communication in Unix systems, and unfortunately, very few methods can be ported across all UNIX systems (the only half-duplex pipeline, which is also the most primitive form of communication). Linux, as an emerging operating system, supports almost all of the common inter-process communication methods under Unix: pipelines, message queues, shared memory, semaphores, socket interfaces , and so on. Below we will introduce each.

Pipeline  

Pipelines are the oldest way of interprocess communication, including nameless pipes and two of known pipelines used for communication between parent and child processes, which are used to communicate between any two processes running on the same machine. Nameless pipes are created by the pipe () function:

#include <unistd.h>
int pipe (int filedis[2]);
Parameter Filedis returns two file descriptor: filedes[0] Open for Read, filedes[1] for write. The output of filedes[1] is the input of filedes[0]. The following example demonstrates how to communicate between parent and child processes.

#define INPUT 0
#define OUTPUT 1

void Main () {
int file_descriptors[2];
/* Define child process number */
pid_t pid;
Char buf[256];
int returned_count;
/* Create a nameless pipe */
Pipe (file_descriptors);
/* Create Child process */
if (PID = fork ()) = =-1) {
printf ("Error in fork/n");
Exit (1);
}
/* Execute child process */
if (PID = = 0) {
printf ("In the spawned (child) process.../n");
/* Child process writes data to the parent process, closes the read-side of the pipeline */
Close (File_descriptors[input]);
Write (File_descriptors[output], "test data", strlen ("test Data"));
Exit (0);
} else {
/* Execute Parent Process */
printf ("In the Spawning (parent) process.../n");
/* The parent process reads the data written by the child process from the pipeline, closing the write end of the pipeline */
Close (File_descriptors[output]);
Returned_count = Read (File_descriptors[input], buf, sizeof (BUF));
printf ("%d bytes of data received from spawned process:%s/n",
Returned_count, BUF);
}
}
Under the Linux system, a well-known pipeline can be created in two ways: command-line mode Mknod system calls and function Mkfifo. Both of the following paths generate a well-known pipeline named Myfifo in the current directory:
Mode one: Mkfifo ("Myfifo", "RW");
Mode two: Mknod Myfifo p
Once a named pipeline is generated, it can be manipulated using generic file I/O functions such as open, close, read, write, and so on. Here is a simple example, assuming that we have created a well-known pipeline named Myfifo.
/* Process one: Read the famous pipe */
#include <stdio.h>
#include <unistd.h>
void Main () {
FILE * IN_FILE;
int count = 1;
Char buf[80];
In_file = fopen ("Mypipe", "R");
if (In_file = = NULL) {
printf ("Error in fdopen./n");
Exit (1);
}
while ((count = Fread (buf, 1, in_file)) > 0)
printf ("Received from pipe:%s/n", buf);
Fclose (In_file);
}
/* Process two: Write a famous pipeline */
#include <stdio.h>
#include <unistd.h>
void Main () {
FILE * OUT_FILE;
int count = 1;
Char buf[80];
Out_file = fopen ("Mypipe", "w");
if (Out_file = = NULL) {
printf ("Error opening pipe.");
Exit (1);
}
sprintf (BUF, "This was test data for the named pipe example/n");
Fwrite (buf, 1, out_file);
Fclose (Out_file);
}

Message Queuing Message Queuing is used to run interprocess communication on the same machine, which is similar to a pipeline and is a queue used to hold messages in the system kernel, which appears as a list of messages in the system kernel. The structure of the nodes in the message list is declared with MSG.
In fact, it is a gradually phased out of communication, we can use a stream pipeline or a set of interfaces to replace it, so we do not explain this way, it is recommended that readers ignore this way.

Shared Memory shared memory is the fastest way to communicate between processes running on the same machine, because data does not need to replicate between different processes。 A shared memory area is typically created by a process, and the remaining processes read and write to the memory area. There are two ways of getting shared memory: mapping/dev/mem devices and memory image files. The former does not bring additional overhead to the system, but it is not commonly used in reality, because it controls access to actual physical memory, which, under the Linux system, can only be done by restricting the memory access of the Linux system, which is certainly not practical. The common way is to use the SHMXXX function family to realize the storage using shared memory.
The first function to be used is shmget, which obtains a shared storage identifier.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int Shmget (key_t key, int size, int flag);
This function is somewhat similar to the familiar malloc function, which is used as a shared memory by the request to allocate size memory. A non-negative integer identifier for each IPC structure in the kernel of the Linux system so that a message queue is sent with a reference to the identifier. This identifier is the kernel from the IPC structure of the keyword, this keyword is the first function above the key. The data type key_t is defined in the header file Sys/types.h, which is a long-shaped data. This keyword is also encountered in the chapters that follow us.

When shared memory is created, the rest of the process can call Shmat () to connect it to its own address space.
void *shmat (int shmid, void *addr, int flag);
Shmid the shared storage identifier returned for the Shmget function, the addr and flag parameters determine how the address of the connection is determined, the return value of the function is the actual address to which the process data segment is connected, and the process can read and write to the process.
The point of note for interprocess communication using shared storage is to synchronize data access, and you must ensure that when a process reads the data, the data it wants is already written. Typically, semaphores are used to synchronize the access to shared storage data, and in addition, some flags such as Shm_lock, Shm_unlock, and so on, can be set by using the SHMCTL function for shared storage memory.

Signal Volume Semaphores are also called semaphores, which are used to coordinate data objects between different processes, and the most important application is interprocess communication in the previous section of shared memory mode. Essentially, a semaphore is a counter that is used to record access to a resource, such as shared memory. In general, in order to get a shared resource, the process needs to do the following:
(1) test the semaphore that controls the resource.
(2) If the value of this semaphore is positive, the resource is allowed to be used. The process will reduce the semaphore by 1.
(3) If the semaphore is 0, the resource is currently unavailable, the process goes to sleep until the semaphore value is greater than 0, the process is awakened, and the step is transferred (1).
(4) When the process no longer uses a semaphore-controlled resource, the semaphore value is added 1. If there is a process waiting for this semaphore at this time, the process is awakened.
The status of the semaphore is maintained by the Linux kernel operating system and not by the user process. We can see the definition of each structure that the kernel uses to maintain semaphore status from the/usr/src/linux/include/linux/sem.h file. A semaphore is a collection of data that a user can use individually for each element of the collection. The first function to invoke is Semget, which is used to obtain a semaphore ID.

struct SEM {
Short sempid;/* pid of the last Operaton */
ushort semval;/* Current Value */
ushort semncnt;/* num procs awaiting increase in Semval */
ushort semzcnt;/* num procs Awaiting semval = 0 */
}

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int Semget (key_t key, int nsems, int flag);

Key is the keyword for the IPC structure that was previously spoken, and flag will decide in the future whether to create a new semaphore collection or to reference an existing semaphore collection. Nsems is the number of semaphores in the collection. If you are creating a new collection (typically in the server), you must specify Nsems, or if you are referencing an existing semaphore collection (typically in the client), specify Nsems as 0.

The SEMCTL function is used to manipulate the semaphore.
int semctl (int semid, int semnum, int cmd, Union semun Arg);
The different operations are implemented by the CMD parameter, which defines 7 different operations in the header file sem.h, which can be used as reference in the actual programming.

The SEMOP function automatically executes an array of operations on the semaphore set.
int semop (int semid, struct sembuf semoparray[], size_t nops);
Semoparray is a pointer to an array of semaphore operations. NOPS Specifies the number of operations in the array.

Below, let's look at a specific example, it creates a specific IPC structure of the keyword and a semaphore, establishes the index of this semaphore, modifies the value of the semaphore to which the index points, and finally clears the semaphore. In the following code, the function Ftok generates the only IPC keyword we said above.

#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
void Main () {
key_t Unique_key; /* Define an IPC keyword */
int id;
struct SEMBUF lock_it;
Union Semun Options;
int i;

Unique_key = Ftok (".", ' a '); /* Generate the keyword, the character ' A ' is a random seed */
/* Create a new set of semaphores */
id = semget (unique_key, 1, ipc_creat | Ipc_excl | 0666);
printf ("Semaphore id=%d/n", id);
Options.val = 1; /* Set Variable values */
Semctl (ID, 0, setval, options); /* Set the semaphore for index 0 */

/* Print out the value of the semaphore */
i = semctl (ID, 0, getval, 0);
printf ("Value of semaphore at index 0 is%d/n", i);

/* Reset semaphore below */
Lock_it.sem_num = 0; /* Set which semaphore */
Lock_it.sem_op =-1; /* Define ACTION */
LOCK_IT.SEM_FLG = ipc_nowait; /* Operation mode */
if (Semop (ID, &lock_it, 1) = =-1) {
printf ("Can not lock semaphore./n");
Exit (1);
}

i = semctl (ID, 0, getval, 0);
printf ("Value of semaphore at index 0 is%d/n", i);

/* Clear the semaphore */
Semctl (ID, 0, ipc_rmid, 0);
}
Semget ()


You can use the system call Semget () to create a new semaphore set, or to access an already existing semaphore set:

System call: Semget ();
Prototype: Intsemget (key_t key,int nsems,int SEMFLG);
Return value: If successful, the IPC identifier of the semaphore set is returned. If it fails, return -1:errno=eaccess (no permissions)
Eexist (semaphore set already exists, cannot be created)
EIDRM (semaphore set has been removed)
ENOENT (semaphore set does not exist and no ipc_creat is used)
Enomem (there is not enough memory to create a new semaphore set)
ENOSPC (out-of-bounds) the first parameter of the system call Semget () is the keyword value (typically returned by the system call Ftok ()). The system kernel compares this value to the key values of other semaphore sets that exist in the system. The open and access operation is related to the contents of the parameter semflg. Ipc_creat creates a semaphore set if the semaphore set does not exist in the system core. IPC_EXCL when used in conjunction with Ipc_creat, the call fails if the semaphore set already exists. If Ipc_creat is used alone, Semget () either returns the identifier of the newly created semaphore set or the identifier for the semaphore that already exists in the system for the same key value. If Ipc_excl and ipc_creat are used together, either return the identifier of the newly created semaphore set or return-1. Ipc_excl use alone is meaningless. The parameter nsems indicates the number of semaphores that should be created in a new semaphore set. The maximum number of semaphores in a semaphore set is defined in linux/sem.h: #defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
Here is a program to open and create a semaphore set:
Intopen_semaphore_set (key_t keyval,int numsems)
{
Intsid;
if (!numsems)
Return (-1);
if ((Sid=semget (mykey,numsems,ipc_creat|0660)) ==-1)
{
Return (-1);
}
return (SID);
}
};============================================================== Semop ()


System call: Semop ();
Call prototype: int semop (int semid,struct sembuf*sops,unsign ednsops);
Return value: 0, if successful. -1, if failure: Errno=e2big (nsops greater than the maximum number of OPS)
eaccess (Insufficient authority)
Eagain (ipc_nowait is used, but the operation cannot continue)
Efault (the address pointed to by SOPs is invalid)
EIDRM (semaphore set has been removed)
EINTR (receive other signals when sleeping)
EINVAL (semaphore set does not exist, or semid is not valid)
Enomem (using Sem_undo, but not enough memory to create the required data structure)
Erange (semaphore value out of range)

The first parameter is a keyword value. The second parameter is a pointer to the array that will be manipulated. The third parameter is the number of operations in the array. The parameter SOPs points to an array that consists of sembuf. This array is defined in linux/sem.h:/*semop Systemcall takes an array of these*/
structsembuf{
Ushortsem_num;/*semaphore Index in array*/
Shortsem_op;/*semaphore operation*/
Shortsem_flg;/*operation flags*/
Sem_num the number of semaphores that will be processed.
Sem_op the action to perform.
SEM_FLG operation Flag. If the sem_op is a negative number, the semaphore subtracts its value. This is related to the amount of resources controlled by the semaphore. If ipc_nowait is not used, the calling process goes to sleep until the semaphore-controlled resource can be used. If Sem_op is a positive number, the semaphore is added to its value. This is how the process releases semaphore-controlled resources. Finally, if Sem_op is 0, then the calling process will call sleep () until the semaphore value is 0. This is used when a process waits for a fully idle resource. =============================================================== Semctl ()


System call: Semctl ();
Prototype: int semctl (int semid,int semnum,int cmd,union semunarg);
Return value: If successful, it is a positive number.
If it fails, it is -1:errno=eaccess (insufficient permissions)
Efault (arg points to an invalid address)
EIDRM (semaphore set has been removed)
EINVAL (semaphore set does not exist, or semid is not valid)
Eperm (Euid without cmd right)
Erange (semaphore value out of range)

The system calls Semctl to perform control operations on the semaphore set. This is very similar to the system call Msgctl in Message Queuing. However, the parameters of the two system calls are slightly different. Because the semaphore is generally used as a semaphore set, instead of a single semaphore. Therefore, in the operation of the signal volume set, not only to know the IPC key value, but also to know the specific signal volume concentration. Both system calls use parameter cmd, which is used to indicate the specific command to be manipulated. The last parameter in both system calls is not the same. In system call Msgctl, the last parameter is a pointer to the data structure used in the kernel. We use this data structure to get some information about Message Queuing, and to set or change the access rights and users of the queue. However, additional optional commands are supported in semaphores, which requires a more complex data structure.
The first parameter of the system call SEMCTL () is the keyword value.    The second parameter is the semaphore number. The commands you can use in parameter cmd are as follows:
· Ipc_stat reads the data structure of a semaphore set Semid_ds and stores it in the BUF parameter in Semun.
· Ipc_set sets the element ipc_perm in the data structure Semid_ds of the semaphore set, whose value is taken from the BUF parameter in Semun.
· Ipc_rmid removes the semaphore set from memory.
· The getall is used to read the values of all semaphores in the semaphore set.
· GETNCNT returns the number of processes that are waiting for a resource.
· Getpid returns the PID of the last process that performed the SEMOP operation.
· Getval returns the value of a single semaphore in the semaphore set.
· GETZCNT returns the number of processes that are waiting for a fully idle resource.
· SetAll sets the value of all semaphores in the semaphore set.
·    Setval sets the value of a single semaphore in the semaphore set. The parameter arg represents an instance of a Semun. Semun is defined in the linux/sem.h:
/*arg for Semctl systemcalls.*/
unionsemun{
Intval;/*value for setval*/
Structsemid_ds*buf;/*buffer for ipc_stat&ipc_set*/
Ushort*array;/*array for getall&setall*/
Structseminfo*__buf;/*buffer for ipc_info*/
Void*__pad; Val is used when executing the setval command. BUF is used in the Ipc_stat/ipc_set command. Represents the data structure of the semaphore used in the kernel. The pointer used by array when using the Getall/setall command.
The following program returns the value of the semaphore. When the Getval command is used, the last parameter in the call is ignored: Intget_sem_val (intsid,intsemnum)
{
Return (Semctl (sid,semnum,getval,0));
The following is an example of a practical application: #defineMAX_PRINTERS5
Printer_usage ()
{
int x;
for (x=0;x<max_printers;x++)
printf ("printer%d:%d/n/r", X,get_sem_val (sid,x));
The following program can be used to initialize a new semaphore value: void init_semaphore (int sid,int semnum,int initval)
{
Union semunsemopts;
Semopts.val=initval;
Semctl (sid,semnum,setval,semopts);
Note that the last parameter in system call Semctl is a copy of a union type, not a pointer to a union type.


Socket interface

Socket programming is one of the main ways to implement inter-process communication between Linux and most other operating systems. Our well-known WWW service, FTP service, Telnet service, etc. are all based on a set of interface programming. The socket interface is also suitable for inter-process communication within the same computer, in addition to the offsite computer processes. The classic textbook on the set of interfaces is also written by Richard Stevens, "UNIX Network programming: Networked APIs and sockets," and a photocopy of the book was published by Tsinghua Press. It is also one of the necessary books for Linux programmers.
In this part of the content, you can refer to the author of another article, "Design your Own network ant", there are several sets of common interface functions of the introduction and sample programs. This part is probably the most attention and the most attractive part of the Linux interprocess communication programming, after all, the Internet is developing at an incredible speed around us, and if a programmer is designing his next program without considering the network, considering the Internet, It can be said that his design is difficult to succeed.

Process/thread Comparison of Linux processes and Win32

Familiar with the WIN32 programming people must know, WIN32 process management way and Linux has a very big difference, in Unix, only the concept of the process, but there is a "thread" concept in WIN32, then what is the difference between Linux and WIN32 here?
The process/thread in WIN32 is inherited from OS/2. In WIN32, "process" refers to a program, and "thread" is an execution "clue" in a "process". From the core, WIN32 's multi-process and Linux are not much different, in the WIN32 line friend equivalent to the Linux process, is a code that is actually executing. However, there are shared data segments between threads in the same process in WIN32. This is the biggest difference from the Linux process.
The following program shows how WIN32 the next process starts a thread.

int g;
DWORD WINAPI childprocess (lpvoid lpparameter) {
int i;
for (i = 1; I <1000; i + +) {
G + +;
printf ("This is a child Thread:%d/n", g);
}
ExitThread (0);
};

void Main ()
{
int ThreadID;
int i;
g = 0;
CreateThread (null, 0, childprocess, NULL, 0, &threadid);
for (i = 1; I <1000; i + +) {
G + +;
printf ("This is the Parent Thread:%d/n", g);
}
}

Under WIN32, using the CreateThread function to create a thread, unlike the creation process under Linux, the WIN32 thread does not run from the creation point, but rather the CreateThread specifies a function from which the thread starts running. This program, like the previous Unix program, prints 1000 messages each from two threads. ThreadID is the thread number of the child thread, and the global variable g is the child thread that is shared with the parent thread, which is the biggest difference from Linux. As you can see, the WIN32 process/thread is more complex than Linux, and it is not difficult for Linux to implement a thread like WIN32, so long as the fork is called, the child process calls the ThreadProc function, and the shared data area is opened for the global variable. However, a fork-like function cannot be achieved under WIN32. So now the WIN32 C compiler provides library functions that are compatible with most Linux/unix library functions, but still cannot fork.
For multi-tasking systems, shared data areas are necessary, but also a confusing problem, under WIN32, a programmer can easily forget that the data between threads is shared, when one thread modifies a variable and another thread modifies it, the result is a program problem. But under Linux, because variables are not shared, programmers explicitly specify the data to be shared, making the program clearer and more secure.
As for WIN32 's "process" concept, it means "application", which is the equivalent of an EXEC under UNIX.
Linux also has its own multithreaded function pthread, which is not only different from the Linux process, but also different from the process under WIN32, about pthread introduction and how to write multithreaded programs in Linux environment we will be in another article, "Multithreaded programming under Linux."

Linux interprocess communication mechanism

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.