信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。
以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
信号量控制着资源的操作
是实现 释放操作还是 获取操作
我们这里 就要了解关于信号量的API接口函数
我们就可以编译一个程序来 使用这几个函数
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/sem.h>
//sem.h
union semun{
int val;
};
void sem_init(); //信号量初始值: 1
void sem_p();
void sem_v();
void sem_destory();
P操作:我们将申请信号量称为P操作,申请信号量的本质就是申请获得临界资源中某块资源的使用权限,当申请成功时临界资源中资源的数目应该减一,因此P操作的本质就是让计数器减一。
V操作:我们将释放信号量称为V操作,释放信号量的本质就是归还临界资源中某块资源的使用权限,当释放成功时临界资源中资源的数目就应该加一,因此V操作的本质就是让计数器加一。
#include "sem.h" //sem.c
static int semid; //静态全局变量 --- .data区 本文件有效
void sem_init(){
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
if(semid == -1){ // 创建失败(只需要获取)
semid = semget((key_t)1234,1,0600); //获取
if(semid == -1) exit(1);
}
else{
union semun a;
a.val = 1;
if(semctl(semid,0,SETVAL,a) == -1){
perror("semctl error");
exit(1);
}
}
}
void sem_p(){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1; //获取资源
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1){
perror("semop err");
exit(1);
}
}
void sem_v(){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1; //释放资源
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1){
perror("semop err");
exit(1);
}
}
void sem_destory(){
if(semctl(semid,0,IPC_RMID) == -1){
perror("semctl rm error");
exit(1);
}
}