信号量与其他IPC方式不同,它不是进行消息的交互,而是从当一个计数器的功能,它用于实现进程间的互斥和同步。(给我的感觉是有点像JAVA中线程的🔒)
举一个例子:两个人想要进入同一个密室去处理一些事情,钥匙也只有一把,每次只能有一个人拿一把钥匙进入密室。第一个人拿着钥匙进入密室,第二个人只能在外边等待,直到第一个人拿着钥匙出来之后,放回钥匙,才能进入密室处理自己的事情。信号量在这个过程中就充当着钥匙的作用,而密室则是充当临界资源的角色
特点:
- 信号量用于进程间的同步,若要在进程间传递数据需要结合共享内存使用
- 信号量基于操作系统的P(拿🔒)V(放回🔒)操作,程序对信号量的操作都是原子操作
- 每次对信号量的PV操作不仅限于对信号量的+1或-1操作,可以加减任何正整数
- 支持信号量组(多把🔑)
原型:
#include <sys/sem.h>
int semget(key_t ket,int num_sems,int sem_flags);
//创建或获取一个信号量组:成功返回信号量集的ID,失败返回-1
int semop(int semid,struct sembuf semoparray[],size_t numops);
//对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
int semctl(int semid,int sem_num,int cmd,...)
//控制信号量的相关信息
demo:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
//int semget(key_t key, int nsems, int semflg);
//int semop(int semid, struct sembuf *sops, size_t nsops(几个信号量));
//int semctl(int semid, int semnum, int cmd, ...);
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) */
};
//P操作
void pGetKey(int id){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op--;
buf.sem_flg = SEM_UNDO;
semop(id,&buf,1);
printf("Get key successfully!\n");
return;
}
//V操作:
void vPutBackKey(int id){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op++;
buf.sem_flg = SEM_UNDO;
semop(id,&buf,1);
printf("Put back key successfully!\n");
return;
}
int main(){
int pid;
key_t key;
key = ftok(".",5);
union semun cmdinit;
cmdinit.val = 0;
int semid = semget(key,1,IPC_CREAT|0666);
printf("semid = %d\n",semid);
if(semctl(semid,0,SETVAL,cmdinit) == 0){
//SETVAL是初始化信号量
printf("Semctl success!\n");
}else{
printf("Semctl failure\n");
perror("Why");
}
pid = fork();
if(pid > 0){
pGetKey(semid);
printf("This is father:\n");
//pGetKey(semid);
vPutBackKey(semid);
semctl(semid,0,IPC_RMID);
//移除当前信号量
}else if(pid == 0){
printf("This is son:\n");
vPutBackKey(semid);
}else{
printf("Fork error!\n");
}
return 0;
}
运行结果:
semid为0有可能是ftok时数字可能在以前的进程中有重复
该程序的整体思路就是 先semget获取信号量的id方便进行操作,用semctl来初始化锁的相关信息(SETVAL),此时semctl就需要第四个参数(一个联合体),随后定义PV操作的函数(先初始化结构体,然后semop信号量),最后根据需求来semop控制进程谁先进行,谁后执行。
信号量常和共享内存当配使用,后续demo等写出来之后再放出来