This article will describe the mechanism of a communication between processes-the semaphore. Note: Please do not confuse it with the previously mentioned signal, the signal and the semaphore are different two kinds of things. For more information about the signal, you can read my other article: Linux interprocess Communication-signal. The following is an explanation of the signal volume.
first, what is the signal volume
To prevent a series of problems that arise from the simultaneous access of multiple programs to a shared resource, we need a method that can be authorized by generating and using tokens, and at any one time there can be only one critical region that executes thread access code. A critical region is a code that performs data updates that needs to be executed exclusively. And semaphores can provide such an access mechanism, so that a critical section at the same time only one thread is accessing it, that is, the semaphore is used to attune process access to shared resources.
A semaphore is a special variable whose access is atomic, and only allows it to wait (that is, p (signal variable)) and send (that is, V (signal variable)) information operation. The simplest semaphore is a variable of only 0 and 1, which is also the most common form of semaphore, called the binary semaphore. A semaphore that can take multiple positive integers is called a generic semaphore. The main discussion here is the binary signal volume.
second, the operation principle of the signal volume
Since semaphores can only perform two operation waits and send signals, namely P (SV) and V (SV), they behave like this:
P (SV): If the value of SV is greater than 0, it is reduced by 1, and if its value is zero, the execution of the process is suspended.
V (SV): If another process is suspended because it waits for the SV, let it run again, and if no process is suspended because it waits for the SV, add 1 to it.
For example, two processes share the semaphore SV, and once one of the processes performs a P (SV) operation, it will get the semaphore and can enter the critical section, reducing the SV by 1. The second process is prevented from entering the critical section because when it attempts to execute P (SV), the SV is 0, it is suspended to wait for the first process to leave the critical area and performs a V (SV) Release semaphore, and the second process can resume execution.
third, the Linux signal volume mechanism
Linux provides a well-designed set of semaphore interfaces to operate on signals that are not just for binary semaphores, but are described below, but note that these functions are used to manipulate the set of semaphore values. They are declared in the header file sys/sem.h .
1. Semget () function
Its role is to create a new semaphore or to obtain an existing semaphore, the prototype is:
int semget(key_t key, int num_sems, int sem_flags);
The first parameter, key, is an integer value (unique not 0), and an unrelated process can access a semaphore, which represents a resource that the program may want to use, and the program accesses all semaphores indirectly, by calling the Semget () function and providing a key. The system generates a corresponding signal identifier (the return value of the Semget () function), and only the Semget () function uses the semaphore key directly, and all other semaphore functions use the semaphore identifier returned by the Semget () function. If multiple programs use the same key value, key will be responsible for coordinating the work.
The second parameter, Num_sems, specifies the number of semaphores required, and its value is almost always 1.
The third parameter, Sem_flags, is a set of flags that, when you want to create a new semaphore when the semaphore does not exist, you can do a bitwise OR operation with the value ipc_creat. When the IPC_CREAT flag is set, the given key is not an error if it is a key that already has a semaphore. and Ipc_creat | IPC_EXCL can create a new, unique semaphore that returns an error if the semaphore already exists.
The Semget () function successfully returns a corresponding signal identifier (not 0), and the failure returns-1.
2. Semop () function
Its function is to change the value of the semaphore, the prototype is:
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
SEM_ID is the semaphore identifier returned by Semget (), and the SEMBUF structure is defined as follows:
struct sembuf{short sem_num;//Unless a set of semaphores is used, it is 0 short sem_op; The amount of data that the semaphore needs to change in a single operation, usually two numbers, one is-1, that is, the P (wait) operation, //One is +1, which is the V (Send signal) operation. Short sem_flg;//usually Sem_undo, which causes the operating system to trace the signal, //And when the process does not release the semaphore and terminates, the operating system releases the semaphore};
3. Semctl () function
This function is used to control the semaphore information directly, and its prototype is:
int semctl(int sem_id, int sem_num, int command, ...);
If there is a fourth argument, it is usually a union semum structure, defined as follows:
Union Semun { int val; struct Semid_ds *buf; unsigned short *arry;};
The first two parameters are the same as in the previous function, and command is usually one of the following two values
setval: Used to initialize the semaphore to a known value. P This value is set by the Val member in the Union Semun, which is set before the semaphore is used for the first time.
ipc_rmid: Used to delete a semaphore identifier that has not been used for further use.
Iv. process using semaphore communication
Here's an example of how the semaphore is used to communicate between processes, an example of two identical programs outputting data to the screen at the same time, and we can see how to use semaphores to coordinate the work of two processes so that only one process can output data to the screen at once. Note that if the program is first called (in order to differentiate, the first time the program is called with a character to output to the screen as a parameter), you need to call the Set_semvalue () function to initialize the signal and set the message character to the first character of the parameter passed to the program, The first process that starts is also responsible for the deletion of semaphores. If you do not delete the semaphore, it will continue to exist in the system, even if the program has exited, it may cause problems the next time you run this program, and the semaphore is a limited resource.
Call Semget () in the main function to create a semaphore that returns a semaphore identifier stored in the global variable sem_id, which is then used by subsequent functions to access the semaphore.
The source file is seml.c and the code is as follows:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h>//union semun//{//int Val;//struct semid_ds *buf;//unsigned short *arry;//};static int sem_id = 0;static int set_semvalue (); static void Del_semv Alue (); static int semaphore_p (); static int semaphore_v (); int main (int argc, char *argv[]) {char message = ' X '; int i = 0;// Create semaphore sem_id = Semget ((key_t) 1234, 1, 0666 | Ipc_creat); if (argc > 1) {//program is first called, initialize semaphore if (!set_semvalue ()) {fprintf (stderr, "Failed to initialize semaphore\n"); Exit (exit_failure);} Sets the information to output to the screen, that is, the first character of its argument, message = Argv[1][0];sleep (2);} for (i = 0; i < ++i) {//Enter critical section if (!semaphore_p ()) {exit (exit_failure);} Output data to the screen printf ("%c", message),//clears the buffer and then sleeps at random time fflush (stdout); Sleep (rand ()% 3);//Output Data printf ("%c") to the screen before leaving the critical section. message); Fflush (stdout);//Leave the critical section, and resume the loop if (!semaphore_v ()) {exit (exit_failure) after a random time of sleep;} Sleep (rand ()% 2);} Sleep;p rintf ("\n%d-finished\n", Getpid ()), if (argc > 1) {//If the program was first called, delete the semaphore before exiting Sleep (3);d el_semvalue ();} Exit (exit_success);} The static int set_semvalue () {///is used to initialize the semaphore, which must be done before using the semaphore Union Semun sem_union;sem_union.val = 1;if (Semctl (sem_id, 0, Setval, s em_union) = =-1) {return 0;} return 1;} static void Del_semvalue () {//delete semaphore Union Semun sem_union;if (Semctl (sem_id, 0, ipc_rmid, sem_union) = =-1) {fprintf (stderr , "Failed to delete semaphore\n");}} static int semaphore_p () {///= 1 operation on semaphore, i.e. wait P (SV) struct Sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_op = -1;//p () sem_b.sem_ FLG = Sem_undo;if (Semop (sem_id, &sem_b, 1) = =-1) {fprintf (stderr, "semaphore_p failed\n"); return 0;} return 1;} static int Semaphore_v () {///This is a release operation that makes the signal available, that is, send signal V (SV) struct Sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_op = 1;//V () se M_B.SEM_FLG = Sem_undo;if (Semop (sem_id, &sem_b, 1) = =-1) {fprintf (stderr, "Semaphore_v failed\n"); return 0;} return 1;}
The results of the operation are as follows:
Note: The critical section of this program is the code in the middle of the semaphore_p () and Semaphore_v () functions of the main function for loop.
Example Analysis:
Run two instances of a program at the same time, note that the first time you run it, add a character as a parameter, such as the character ' O ' in this example, to distinguish whether it is the first call and the character output to the screen. Because each program prints a character before it enters the critical section and before it leaves the critical section, each character should appear in pairs, as you see in the output. In the main function loop we can see that every time the process wants to access stdout (standard output), that is, to output characters, each time to check whether the semaphore is available (that is, stdout is not being used by another process). Therefore, when a process a calls the function semaphore_p () enters the critical section, after the output character, call sleep (), another process B may want to access stdout, but the semaphore p request operation fails, can only suspend its own execution when process a calls the function semaphore _v () leaves the critical section and process B is immediately resumed. Then process A and process B have been circulating 10 times.
v. Comparative examples-Inter-process resource competition
Look at the above example, you may not quite understand, but it doesn't matter, I would like to illustrate with another example, it implements the same function as in the previous example, the same way, are two identical processes, while outputting characters to stdout, but not using the semaphore, Two processes compete stdout with one another. Its code is very simple, the file name is normalprint.c, the code is as follows:
#include <stdio.h> #include <stdlib.h>int main (int argc, char *argv[]) {char message = ' X '; int i = 0;if (argc &G T 1) {message = Argv[1][0];} for (i = 0; i < ++i) {printf ("%c", Message), Fflush (stdout); Sleep (rand ()% 3);p rintf ("%c", message); Fflush (stdout); s Leep (rand ()% 2);} Sleep;p rintf ("\n%d-finished\n", Getpid ()); exit (exit_success);
The results of the operation are as follows:
Example Analysis:
From the above output, we can see that the characters ' X ' and ' O ' are not always paired, as in the previous example, because when the first process a character is called sleep, another process B immediately outputs and sleeps, while process a wakes up and then resumes execution of the output, as well as the same process B. So the output of the character is not a pair of appearance. These two processes compete in the stdout of this common resource. In comparison with two examples, I think the meaning and use of semaphores should be clearer.
Vi. Summary of the signal volume
A semaphore is a special variable whose access is atomic, and only allows it to wait (that is, p (signal variable)) and send (that is, V (signal variable)) information operation. We usually use signals to solve the problem of multiple process access to the same resource, so that at any one time there can be only one critical region to execute thread access code, or it can be said to coordinate access to the same resource between processes, that is, for the synchronization process.
Attention:
The process in the example is divided into two types, a process with command-line arguments at run time, and a process with no parameters at run time. The former is responsible for creating the semaphore, setting the initial value and destroying it, while the latter directly obtains and uses the former to create and set the signal volume.
Reference:
http://blog.csdn.net/ljianhui/article/details/10243617
"Linux High performance Server Programming"
Linux interprocess communication-semaphore semget (), Semop (), Semctl ()