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-using signals. The following is an explanation of the signal volume.
I. What is a semaphore in order to prevent a series of problems caused by multiple programs accessing a shared resource at the same time, 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. Ii. How the Semaphore works because the semaphore can only perform two operation waits and sends the signal, namely P (SV) and V (SV), their behavior is this: P (SV): If the value of SV is greater than 0, give it minus 1, if its value is zero, suspend the execution of the process 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 semaphore mechanism Linux provides a set of well-designed 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 function 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 It 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;//semaphore data that needs to be changed in one operation, usually two numbers, one is-1, that is, p (wait) operation, //One is +1, i.e. V (send signal) operation. The short sem_flg;//is usually sem_undo, which causes the operating system to trace the signal, //And when the process terminates without releasing the semaphore, the operating system releases the semaphore};
3. Semctl function This function is used to directly control the semaphore information, 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 arguments are the same as in the previous one, and the command is usually one of the following two values: used to initialize the semaphore to a known value, Setval. 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 below is an example of how the semaphore is used to communicate between processes, this example is two identical programs simultaneously output data to the screen, we can see how to use semaphores to make two processes work together, so that only one process at a time can output data to the screen. 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 argument 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{INTVal struct Semid_ds *Buf unsigned short *Arry;}; static int sem_id = 0; static intSet_semvalue (); static voidDel_semvalue (); static intSemaphore_p (); static intSemaphore_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{//The program is called for the first time, initialize the semaphore if (!)Set_semvalue ()) {fprintf (stderr, "Failed to initialize semaphore\n"); Exit (Exit_failure); }//sets the information to be output to the screen, that is, the first character of its argument, message = Argv[1][0]; Sleep (2); } for (i = 0; i < 10; + +)i) {//Enter the critical section if (!Semaphore_p ()) exit (Exit_failure); Output data to the screen printf ("%c", message); Clears the buffer and then sleeps at random timeFflush (stdout); Sleep (rand ()% 3); Output data to the screen again before leaving the critical section printf ("%c", message); Fflush (stdout); Leave the critical section, hibernate after a random time to continue looping if (!Semaphore_v ()) exit (Exit_failure); Sleep (rand ()% 2); } Sleep (10); printf ("\n%d-finished\n", Getpid ()); if (argc > 1) {//If the program is called for the first time, delete the semaphore before exiting sleep (3); Del_semvalue (); } exit (exit_success);} static intSet_semvalue () {//used to initialize semaphores, this must be done before using semaphoresUnion Semun Sem_union; Sem_union.val = 1; if (Semctl (sem_id, 0, setval, sem_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 for semaphore, i.e. wait for 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 () SEM_B.SEM_FLG = Sem_undo, if (Semop (sem_id, &sem_b, 1) = =-1 ) {fprintf (stderr, "Semapho Re_v failed\n "); return 0 ;} return 1 ;}
The result of the operation is 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 execution. Then process A and process B have been circulating 10 times. Contrast example--process of resource competition look at the above example, you may not quite understand, but it doesn't matter, I would like to illustrate in another example, it implements the same function as in the previous example, the same way, are two identical processes, while outputting characters to stdout, Just without the use of semaphores, two processes compete against each other stdout. 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 '; C4/>int i = 0; if (argc > 1) message = Argv[1][0]; for (i = 0; I < + +i) {printf ("%c", message); Fflush (std Out); Sleep (rand ()% 3), printf ("%c", Message), Fflush (stdout), Sleep (rand ()% 2), sleep (); printf ("\n% d-finished\n ", Getpid ()); Exit (exit_success);}
The results are as follows: Example analysis: From the above output, we can see the characters ' X ' and ' O ' is 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 resumes the output, the same process B does. 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. Six, the sum of the semaphore is a special variable, the program to its access is atomic operation, and only allow 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.
Reprint: http://blog.csdn.net/ljianhui/article/details/10243617
ipc--Signal Volume