IPC Semaphore
Semaphores can be used for communication between processes or between threads within a process. Each semaphore has a semaphore value that will not be less than 0, corresponding to the number of available semaphores. Call sem_init() or sem_open() to assign an initial value to the semaphore value, call sem_post() to increase the semaphore value by 1, and call sem_wait() to decrease the semaphore value by 1. If the current semaphore is 0, the thread that calls sem_wait() is suspended in the waiting queue of the semaphore until the semaphore value is greater than 0 and is available.
Depending on the value of the semaphore (representing the number of available resources), POSIX semaphores can be divided into:
Binary semaphore: The semaphore has only two values: 0 and 1, and the initial value is 1. This is the same as a mutex lock. If the resource is locked, the semaphore value is 0, and if the resource is available, the semaphore value is 1. It is equivalent to having only one key. After the thread gets the key, it needs to unlock it after completing the access to the shared resource, and then put the key back for other threads that need the key. The usage method is the same as the mutex lock. The waiting semaphore function must be used in pairs with the sending semaphore function. It cannot be used alone. You must wait before sending.
Counting semaphore: The value of the semaphore is between 0 and a limit value greater than 1 (POSIX specifies that the maximum limit value of the system must be at least 32767). The count indicates the number of available semaphores. At this time, the send semaphore function can be called individually to send semaphores, which is equivalent to having multiple keys. When a thread gets a key, it consumes one key, and the used key does not need to be put back.
POSIX semaphores are divided into named semaphores and unnamed semaphores:
Named semaphore: Its value is saved in a file and is generally used for synchronization or mutual exclusion between processes.
Unnamed semaphore: Its value is stored in memory and is generally used for synchronization or mutual exclusion between threads.
The POSIX semaphore of the RT-Thread operating system is mainly a wrapper of the RT-Thread kernel semaphore, and is mainly used for communication between threads in the system. The usage is similar to the semaphore of the RT-Thread kernel.
Each semaphore corresponds to a semaphore control block. Before creating a semaphore, you need to define a sem_t semaphore control block. sem_t is a redefinition of the posix_sem structure type, defined in the semaphore.h header file.
The value of an unnamed semaphore is stored in memory and is generally used for synchronization or mutual exclusion between threads. Before use, you must call sem_init() to initialize it.
Initialize an unnamed semaphore
This function initializes an unnamed semaphore sem, initializes the semaphore-related data structure according to the given or default parameters, and puts the semaphore into the semaphore linked list. After initialization, the semaphore value is the given initial value value. This function is a wrapper for the rt_sem_create() function.
This function destroys an unnamed semaphore sem and releases the resources occupied by the semaphore.
Named semaphores, whose values are stored in files, are generally used for synchronization or mutual exclusion between processes. Two processes can operate a named semaphore with the same name. The implementation of named semaphores in the RT-Thread operating system is similar to that of unnamed semaphores. Both are designed for communication between threads and are used in a similar way.
Create or open a named semaphore
This function creates a new semaphore or opens an existing semaphore based on the semaphore name name. The optional values of Oflag are 0, O_CREAT or O_CREAT|O_EXCL. If Oflag is set to O_CREAT, a new semaphore will be created. If Oflag is set to O_CREAT|O_EXCL, NULL will be returned if the semaphore already exists, and a new semaphore will be created if it does not exist. If Oflag is set to 0, NULL will be returned if the semaphore does not exist.
This function will find the semaphore according to the semaphore name name. If the semaphore exists, it will mark the semaphore as detached. Then check the reference count. If the value is 0, the semaphore will be deleted immediately. If the value is not 0, it will not be deleted until all threads holding the semaphore close the semaphore.
When a thread terminates, the semaphore it occupies will be closed. Whether the thread terminates voluntarily or involuntarily, this closing operation will be performed, which is equivalent to reducing the holding count of the semaphore by 1. If the holding count is 0 after decrementing by 1 and the semaphore is already in the detached state, the sem semaphore will be deleted and the resources it occupies will be released.
This function can get the value of the sem semaphore and save it in the memory pointed to by sval, so as to know the number of semaphore resources.
The thread calls this function to obtain the semaphore, which is the encapsulation of the rt_sem_take(sem, RT_WAITING_FOREVER) function. If the semaphore value is greater than zero, it indicates that the semaphore is available, the thread obtains the semaphore, and the semaphore value decreases by 1. If the semaphore value is equal to 0, it indicates that the semaphore is not available, the thread is blocked and enters the suspended state, and queues in a first-in-first-out manner until the semaphore is available.
This function is a non-blocking version of the sem_wait() function and is a wrapper of the rt_sem_take(sem,0) function. When the semaphore is not available, the thread will not block but return directly.
The difference between this function and sem_wait() function is that if the semaphore is not available, the thread will be blocked for abs_timeout duration. After the timeout, the function returns - 1 and the thread will be awakened from the blocked state to the ready state.
This function will release a sem semaphore and is a wrapper of the rt_sem_release() function. If the queue of threads waiting for the semaphore is not empty, it means that there are threads waiting for the semaphore. The first thread waiting for the semaphore will switch from the suspended state to the ready state and wait for system scheduling. If there are no threads waiting for the semaphore, the semaphore value will increase by 1.
The typical case of semaphore usage is the producer-consumer model. A producer thread and a consumer thread operate on the same block of memory, the producer fills data into the shared memory, and the consumer reads data from the shared memory.
This program will create 2 threads and 2 semaphores, one semaphore indicates that the shared data is empty, the other semaphore indicates that the shared data is not empty, and a mutex lock is used to protect shared resources. After the producer thread produces data, it will send a full_sem semaphore to the consumer to notify the consumer thread that data is available. After sleeping for 2 seconds, it will wait for the empty_sem semaphore sent by the consumer thread. After the full_sem sent by the producer, the consumer thread will process the shared data, and after processing, it will send the empty_sem semaphore to the producer thread. The program will continue to loop like this.
Last updated