- A semaphore is a critical resource, and its essence is a counter.
- There are two basic operations of semaphore: P operation and V operation. The P operation is equivalent to decrementing the counter by one, and the V operation is equivalent to adding one to the counter.
- A semaphore describes the number of critical resources it wants to protect. Because the semaphore itself is also a critical resource, the premise of using it to protect other critical resources is to ensure the atomicity of the operation of the semaphore itself.
- POSIX semaphores and SystemV semaphores have the same function, and are both used for synchronous operations to achieve conflict-free access to shared resources. Single POSIX can be used for inter-thread synchronization.
- The operation of the semaphore P is successful, indicating that access to critical resources is allowed.
Common functions for semaphores:
1. Initialize the semaphore
Function prototype: int sem_init(sem_t *sem, int pshared, unsigned int value);
parameter:
pshared: 0 means shared between threads, non-zero means shared between processes.
value: the initial value of the semaphore
2. Destroy the semaphore
Function prototype: int sem_destroy(sem_t *sem);
3. Wait for semaphore
Function prototype: int sem_wait (sem_t *sem);
Function: Waiting for the semaphore, the value of the semaphore will be decremented by one, which is equivalent to performing the P operation on the semaphore.
4. Release semaphore
Function prototype: int sem_post (sem_t *sem);
Function: Release a semaphore, indicating that the resource is used up and the resource can be returned. Adding one to the value of the semaphore is equivalent to performing a V operation on the semaphore.
- The producer-consumer example is based on a linked list, and its space can be dynamically allocated. Now rewrite this program based on a fixed-size circular queue (POSIX semaphore):
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#define M 6
int ring[M];
sem_t semBlank, semData;
void* runC(void *arg){
int i = 0;
int d;
while(1){
sem_wait(&semData);
d = ring[i];
i++;
i %= M;
printf("comsumer done , data is %d\n",d);
sem_post (& semBlank);
sleep(1);
}
}
void* runP(void* arg){
int d = 0;
int i = 0;
while(1){
sem_wait (& semBlank);
ring[i] = rand()%123+1;
d = ring[i];
i++;
i %= M;
printf("product done , data is %d\n",d);
sem_post(&semData);
}
}
int main(){
sem_init (& semBlank, 0, M);
sem_init(&semData,0,0);
srand((unsigned long)time(NULL));
pthread_t t1,t2;
pthread_create(&t1,NULL,runC,NULL);
pthread_create(&t2,NULL,runP,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
sem_destroy(&semBlank);
sem_destroy(&semData);
}
Result presentation:
通过结果我们可以看出,生产者先生产一些数据,等到生产者生产的数据占满整个环形队列时,生产者就停止生产,直到有消费者拿走数据。此时消费者拿走一条数据,生产者就生产一条数据。