概念:
信号灯(semaphore),也叫信号量。它是不同进程 间或一个给定进程内部不同线程间同步的机制。而是通过操作某些内容,达到控制另一进程 阻塞或释放 的操作 。系统5的信号量是由一个或多个信号灯组成的一个集合 其中每一个灯都是单独操作的。
目的:
信号量是用来解决进程/线程之间同步或者互斥问题的一种通信机制,包括一个称为信号量的变量和该信号量下等待资源的进程等待列队。以及对信号量下进行的两个原子操作(PV)。其中,信号量对应于其中的一种资源,去一个非负数的整数。信号量---》资源个数,为0则没有可用资源。
操作:
1、创建获取信号量
2、PV操作
3、删除信号量
API:
创建函数:
semget:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能:
创建获取信号量
参数:
1。密钥
2。信号量个数
3。semflg:IPC_CREAT|0666//权限
返回值:
成功返回信号量ID
失败返回-1,并设置错误码
密钥获取:
采用ftok函数
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:
手动创建或获取key
参数:
1>pathname:工程文件名(带路径)
2>proj_id :工程代号
返回值:
成功返回key
失败返回-1,并设置错误码
//只要参数不变化,总可以找到同一key
PV操作:
P操作:如果有可用资源(信号量值>0)则占用一个资源(信号量值-1,进入临界区代码)没有可用资源(信号值==0)则堵塞,直到系统分配资源给该任务(一直等待到有资源才会唤醒)。
V操作:如果该信号量的等待队列有任务在等待资源,则唤醒一个阻塞任务。如果没有任务等待,则释放一个资源(信号量-1)。
semop
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
功能:
PV操作
参数:
1>semid:信号量的ID
2>sops :struct sembuf * -->结构体指针 了解结构体
struct sembuf{
unsigned short sem_num; /* semaphore number */信号灯下标
short sem_op; /* semaphore operation */操作:+1 -1 +2 -2//PV操作
short sem_flg; /* operation flags */0可阻塞 IPC_NOWAIT不阻塞
}
3>nsops:结构体中利用到的灯的个数:要操作灯的个数
//使用PV操作,最好以一个灯的方式来操作
返回值:
成功返回 0
失败返回 -1,并设置错误码
删除信号量:
设置信号量,也可以说是初始化资源数
通过value进行操作:查询,修改,删除
semctl
#include <sys/types.h>
#include <sys/ipc.h>
include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
功能:
对信号量的操作
参数:
1>semid:信号量的ID
2>semnum:信号灯的下标
3>cmd:操作详情:
IPC_RMID:删除信号量
GETVAL:获取信号灯的Value值
SETVAL:设置信号灯的Value值
4>...:根据操作详情而调用的值
IPC_RMID:NULL
GETVAL: NULL
SETVAL: union semun --->联合体
返回值:
GETVAL:成功获取vlaue值
其他成功返回0
失败返回-1,并设置错误码
返回值!=value值
查找value值:从灯提取value并替代返回值
其他:函数直接返回
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
如何在系统中查看信号量
ipcs -s
如何删除信号量
ipcrm -s 信号量ID
简单示例:
semget1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun {
int val; /* Value for SETVAL *///设置value值
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int main(){
//1>创建或获取信号量
//前提:制作key
key_t key=ftok("1.c",1);
if(key<0){
perror("ftok");
return -1;
}
printf("key为%#x\n",key);
//创建或寻找到信号量
int semid=semget(key,3,IPC_CREAT|0666);
if(semid<0){
perror("semget");
return -1;
}
printf("信号量的ID:%d\n",semid);
//操作:查询vlaue值
int val=semctl(semid,0,GETVAL,NULL);
if(val<0){
perror("semctl1");
return -1;
}
printf("val:%d\n",val);
/*
//2>对信号灯进行操作:P操作
struct sembuf light1={0,-4,0};//给结构体变量赋值 : 0号灯 -2操作 阻塞
int ret=semop(semid,&light1,1);//进程在此处因为0号灯 -2操作,导致阻塞
if(ret<0){
perror("semop");
return -1;
}
printf("test。。。\n");
*/
//操作:设置value值
union semun us;
us.val=5;
int ret=semctl(semid,0,SETVAL,us);
if(val<0){
perror("semctl2");
return -1;
}
//再次查询
val=semctl(semid,0,GETVAL,NULL);
if(val<0){
perror("semctl3");
return -1;
}
printf("val:%d\n",val);
return 0;
}
semget2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main(){
//1>创建或获取信号量
//前提:制作key
key_t key=ftok("1.c",1);
if(key<0){
perror("ftok");
return -1;
}
printf("key为%#x\n",key);
//创建或寻找到信号量
int semid=semget(key,3,IPC_CREAT|0666);
if(semid<0){
perror("semget");
return -1;
}
printf("信号量的ID:%d\n",semid);
//2>对信号灯进行操作:V操作
struct sembuf light1={0,-1,0};//给结构体变量赋值 : 0号灯 -2操作 阻塞
int ret=semop(semid,&light1,1);//进程在此处因为0号灯 -2操作,导致阻塞
if(ret<0){
perror("semop");
return -1;
}
printf("疯狂星期四,不吃的话我真的会谢好吗\n");
return 0;
}
通过semget阻塞1的运行。