信号量
信号量原理
资源计数器(描述资源的可用情况)+PCB等待队列(当资源不可用的时候,将线程放到PCB等待队列进行一个等待)
资源计数器:执行流获取信号量
获取成功信号量计数器进行-1操作;获取失败执行流放入到PCB等待队列。
![](https://img-blog.csdnimg.cn/img_convert/13c0f56d3fe298911456d7a7ce4bbbb1.png)
![](https://img-blog.csdnimg.cn/img_convert/93d8675be85b49f6aeea35f625e28acb.png)
信号量的接口
初始化:int sem_init(sem_t *sem,int pshared,unsigned int value);
sem:信号量,sem_t是信号量的类型
pshared:该信号量是用于进程之间还是线程之间(0:用于线程,全局变量;非0:用于进程)
value:资源的个数,初始化信号量计数器的
等待接口:int sem_wait(sem_t *sem);
1) 对资源计数器进行-1操作
2) 判断资源计数器的值是否小于0。是则堵塞等待,将执行流放入PCB等待队列;不是则接口返回
释放接口:ubt sem_post(sem_t *sem);
1)对资源计数器进行+1操作
2)判断资源计数器的值是否小于等于0。是则通知OCB等待队列;否则不用通知
销毁接口:int sem_destroy(sem_t *sem);
代码模拟:
#include <stdio.h>
#include <semaphore.h> //信号量的头文件
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
sem_t sem; //拥有计数器+PCB等待队列
void sigcallback(int sig){
sem_post(&sem);
}
int main(){
signal(2, sigcallback);
/*
* 为了验证 sem 的接口
* sem_init
* sem_wait
* sem_post
* sem_destroy
* */
sem_init(&sem, 0, 1); //信号量初始维护的资源个数为0
sem_wait(&sem); //第一次获取信号量, 因为资源个数为1, 所以可以获取到
printf("The code has to go here\n");
sem_wait(&sem); //阻塞在这, 因为资源计数器的值为0, 说明资源不可用
printf("The code would be damned if it went this far\n");
return 0;
}
运行结果:
![](https://img-blog.csdnimg.cn/img_convert/18cac5a345a6b67ab3ca51d0278d3a7a.png)
互斥代码模拟:
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
int g_tickets = 100;
sem_t g_lock;
void* thread_startA(void* arg){
pthread_detach(pthread_self());
while(1){
sem_wait(&g_lock); //“加锁操作”
if(g_tickets <= 0){
sem_post(&g_lock); //"解锁操作"
break;
}
printf("i am thread_startA %p, i have %d ticket\n", pthread_self(), g_tickets);
g_tickets--;
sem_post(&g_lock); //"解锁操作"
sleep(1);
}
}
void* thread_startB(void* arg){
pthread_detach(pthread_self());
while(1){
sem_wait(&g_lock); //“加锁操作”
if(g_tickets <= 0){
sem_post(&g_lock); //"解锁操作"
break;
}
printf("i am thread_startB %p, i have %d ticket\n", pthread_self(), g_tickets);
g_tickets--;
sem_post(&g_lock); //"解锁操作"
sleep(1);
}
}
int main(){
sem_init(&g_lock, 0, 1);
pthread_t tid;
int ret = pthread_create(&tid, NULL, thread_startA, NULL);
if(ret < 0){
perror("pthread_create");
return 0;
}
ret = pthread_create(&tid, NULL, thread_startB, NULL);
if(ret < 0){
perror("pthread_create");
return 0;
}
while(1){
sleep(1);
}
sem_destroy(&g_lock);
return 0;
}