Semaphore mechanism in Linux
# Include <sys/SEM. h>
Int semctl (INT sem_id, int sem_num, int command ,...);
Int semget (key_t key, int num_set, int sem_flags );
Int semop (INT sem_id struct sembuf * sem_ops, size_t num_sem_ops );
The header file SYS/SEM. h usually depends on the other two files sys/types. h and sys/IPC. h. In general, they are automatically included by sys/SEM. H, so you do not need to explicitly add the corresponding # include statement for them.
The parameter key acts like a file name. It represents a resource that a program may use. If multiple programs use the same key value, it is responsible for coordination.
1. semget Function
The semget function is used to create a new semaphore or obtain the key of an existing semaphore:
Int semget (key_t key, int num_set, int sem_flags );
The first parameter is an integer. Unrelated processes can use it to access the same semaphore. Only the semget function directly uses the semaphore key. All other semaphore functions use the semaphore identifier returned by the semget function.
Num_sems specifies the number of required semaphores. It is almost always set to 1.
The sem_flags parameter is a set of flags that are very familiar with open functions.
2. semop Function
The semop function is used to change the semaphore value. Its definition is as follows:
Int semop (INT sem_id, struct sembuf * sem_ops, size_t num_sem_ops );
The first sem_id parameter is the semaphore identifier returned by semget. The second parameter sem_ops is a pointer to a structure array. Each array element contains at least a few members:
Struct sembuf
{
Short sem_num;
Short sem_op;
Short sem_flg;
}
The first member sem_num is the semaphore. Unless you need to use a set of semaphores, the value is generally 0.
The value of the sem_op member is the value that the semaphore needs to change in one operation. Usually only two values are used, one is-1, that is, the P operation, which waits for the semaphore to become available. The other is the V operation, which is + 1. It sends signals to indicate that the semaphore is currently available.
The last member sem_flg is usually set to sem_undo. It will be the operating system that tracks the changes made by the current process to this semaphore. If the process terminates without releasing the semaphore, the Operating System Automatically releases the semaphore held by the process.
3. semctl Function
Int semctl (INT sem_id, int sem_num, int command ,...);
The first sem_id parameter is the semaphore identifier returned by semget. The sem_num parameter is used to compile semaphores. this parameter is used when a group of semaphores are used. Generally, the value is 0, indicating that this is the first and only semaphores. The command parameter is the action to be taken. If there is a fourth parameter, it will be a Union semun structure, which contains at least several members:
Union semun
{
Int val;
Struct semid_ds * Buf;
Unsigned short * array;
}
The command parameter in the semctl function can be set with many different values, but only the two values described below are the most commonly used.
Setval: used to initialize the semaphore to a known value. The Val member settings in Union semun are used.
Ipc_rmid: Used to delete a semaphore identifier that is no longer in use.
/* 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 is the first to be called (i.e. it's called with a parameter and argc > 1), a call is made to set_semvalue to initialize the semaphore and op_char is set to X. */#include <unistd.h>#include <stdlib.h>#include <stdio.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 have 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 this program is about to enter the critical section. */ for(i = 0; i < 10; 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 section, 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 is made to clean up 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 SETVAL command in a semctl call. We need to do 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 semaphore'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 that the semaphore becomes available. */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);}