The mechanism of inter-process communication-the semaphore. Note: Please do not confuse it with the previously mentioned signal, the signal and the semaphore are different two kinds of things. A lot of other things about the signal, to be able to read one of my articles:Linux interprocess communication-Uses signals . The following is an explanation of the signal volume.
first, what is the signal volumeto prevent a series of problems that arise when multiple programs visit a shared resource at the same time, we need a way to authorize it by generating and using tokens, and at any one time can only have a critical area of running threads to access code. A critical region is a code that runs data updates that needs to run exclusively. And semaphores can provide this kind of access mechanism, so that a critical section at the same time only one thread is visiting it, that is, the semaphore is used to attune process access to shared resources.
The semaphore is a special variable, and the program's access to it is atomic, and it only agrees to wait for it (i.e. 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. The number of signals 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 volumebecause the semaphore can only perform two operation waits and sends the signal, namely P (SV) and V (SV), their behavior is this:
P Operation is responsible for turns the current process from execution state to blocked state until another process wakes it up.
The operation is: apply for a spare resource (reduce the signal volume by 1), if successful, then exit; if it fails, the process is blocked;
The v Operation is responsible for waking up a blocked process, which has a reference that stores the process information waiting to be woken up.
The action is to release an occupied resource (add 1 to the semaphore) and, assuming a blocked process is found, select a wake-up.
Supplement: the command to view memory sharing information is IPCS [-m|-s|-q] (all words are ipcs-a); the command to view the memory of shared information is IPCS [-m|-s|-q].
For example, two processes share the semaphore SV, and once a process runs the P (SV) operation, it will get the semaphore and be able to enter the critical section, reducing the SV by 1. The second process is prevented from entering the critical section, because when it tries to run P (SV), the SV is 0, it is suspended to wait for the first process to leave the critical area and run V (SV) To release the semaphore, and the second process can resume running.
third, the Linux signal volume mechanismLinux 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 functionits role is to create a new semaphore or to obtain an existing semaphore, the prototype is:
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's access to all semaphores is indirect, and the program first calls the Semget function and provides a key. The system generates a corresponding signal identifier (the return value of the Semget function), only the Semget function uses the semaphore key directly, and all other semaphore functions use the semaphore identifier returned by the Semget function. Assuming that 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 create a new semaphore when the semaphore does not exist, and 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 is able to create a new, unique semaphore, assuming that the semaphore already exists and returns an error.
The Semget function successfully returns a corresponding signal identifier (not 0), and the failure returns -1.
2. Semop functionits function is to change the value of the semaphore, the prototype is:
sem_id is the semaphore identifier returned by Semget, the definition of SEMBUF structure such as the following:
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, typically 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 functionThis function is used to control the semaphore information directly, and its prototype is:
int semctl (int sem_id, int sem_num, int command, ...);
Assuming there is a fourth parameter, it is generally a union semum structure, defined as the following:
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 typically one of the following two valuessetval: 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 communicationHere's a sample of how the semaphore is used to communicate between processes, the example being two identical programs outputting data to the screen at the same time, we can see how to use semaphores to coordinate two processes so that only one process at a time can output data to the screen. Note that assuming that the program was first called (in order to differentiate, the first time a 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 passed to the program's parameters. The first process initiated at the same time is also responsible for the deletion of semaphores. Assuming that the semaphore is not removed, it will continue to exist in the system, even if the program has exited, and it may cause problems the next time you execute the program, and the semaphore is a limited resource.
call Semget in the main function to create a semaphore that returns a semaphore identifier that is stored in the global variable sem_id, and the subsequent function uses that identifier to access the semaphore.
Build a project test:Semun.h
#if defined (__gnu_library__) &&!defined (_sem_semun_undefined)/ * Union Semun are defined by including < sys/sem.h> */#else/ * According to X/open we had to define it ourselves */ Union semun { int val; /* Value for Setval */ struct semid_ds *buf; /* Buffer for Ipc_stat, Ipc_set */ unsigned short int *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for Ipc_info */ }; #endif
MYSEM.C Source code:
/* After the #includes, the function prototypes and the global variable, we come to the main function. There the semaphore is created with a call to Semget, which returns the semaphore ID. If The program was the first to be called (i.e. it's called with a parameter and argc > 1), a call is made to Set_semval UE to initialize the semaphore and Op_char are set to X. */#include <unistd.h> #include <stdlib.h> #include <s tdio.h> #include <sys/sem.h> #include "semun.h" static int set_semvalue (void), static void Del_semvalue (void); static int semaphore_p (void), static int semaphore_v (void), static int sem_id;int main (int argc, char *argv[]) {int i; int pause_time; Char Op_char = ' O '; Srand ((unsigned int) getpid ()); sem_id = Semget ((key_t) 1234, 1, 0666 | Ipc_creat); if (argc > 1) {if (!set_semvalue ()) {fprintf (stderr, "Failed to initialize semaphore\n"); Exit (Exit_failure); } Op_char = ' X '; Sleep (2); }/*Then we had a loop which enters and leaves the critical section ten times. There, we first make a call to Semaphore_p which sets the semaphore to wait, as the L section. */for (i = 0; i < i++) {if (!semaphore_p ()) exit (Exit_failure); printf ("%c", Op_char); Fflush (stdout); Pause_time = rand ()% 3; Sleep (Pause_time); printf ("%c", Op_char); Fflush (stdout);/* After the critical sections, we call Semaphore_v, setting the semaphore available, Before going through the for loop again after a random wait. After the loop, the call to Del_semvalue was made to the code. */if (!SEMAPHORE_V ()) exit (Exit_failure); Pause_time = rand ()% 2; Sleep (Pause_time); } printf ("\n%d-finished\n", Getpid ()); if (argc > 1) {sleep (10); Del_semvalue (); } exit (exit_success);} /* The function Set_semvalue initializes the semaphore using the Setvalcommand in a semctl call. We need to does this before we can use the semaphore. */static int Set_semvalue (void) {Union Semun sem_union; Sem_union.val = 1; if (Semctl (sem_id, 0, setval, sem_union) = =-1) return (0); return (1);} /* The Del_semvalue function has almost the same form, except the call to Semctl uses the command Ipc_rmid to remove the s Emaphore ' s ID. */static void Del_semvalue (void) {Union Semun sem_union; if (Semctl (sem_id, 0, ipc_rmid, sem_union) = =-1) fprintf (stderr, "Failed to delete semaphore\n");} /* Semaphore_p Changes the semaphore by-1 (waiting). */static int semaphore_p (void) {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);} /* Semaphore_v is similar except for setting the Sem_op part of the SEMBUF structure to 1, so, the semaphore becomes a vailable. */static int Semaphore_v (void) {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, "Semaphore_v failed\n"); return (0); } return (1);} Execute the program two times at the same time, compile output:
Xx00xxooxx00xxooxx00xxoo ...