信号量概述
信号量与已经介绍过的IPC结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
int semget(key_t key, int nsems, int semflg);
//对信号量组进程操作,改变信号量的值:成功返回0,失败返回-1
int semop(int semid, struct sembuf *sops, unsigned nsops);
//控制信号量的相关信息
int semctl(int semid, int semnum, int cmd, ...);
int semget(key_t key, int nsems, int semflg);
key就是利用ftok调用的key。
nsems定义的信号量集合中需要几个信号量
semflg 表示获取、创建信号量 宏可以通过man查看
int semop(int semid, struct sembuf *sops, unsigned nsops);
semid 信号量集的ID
struct sembuf *sops
nsops 数组的个数
int semctl(int semid, int semnum, int cmd, …);
semid 信号量集的ID
semnum 需要操作第几个信号量
cmd 通过man semctl查看。
编程实现
编程实现,初始化时临界资源中没有一把锁,我们想要子进程先v操作之后再让父进程pv,代码实现:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
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) */
};
void pGetKey(int id){
struct sembuf set;
set.sem_num = 0; /* 对0号信号量进行处理 */
set.sem_op = -1; /* 每次拿锁之后锁-1 */
set.sem_flg = 0;
semop(id,&set,1);
printf("get the key!\n");
}
void vPutBackKey(int id){
struct sembuf set;
set.sem_num = 0; /* 对0号信号量进行处理 */
set.sem_op = 1; /* 每次把锁放回去之后锁+1 */
set.sem_flg = 0;
semop(id,&set,1);
printf("put back the key!\n");
}
int main(){
int semId;
int pid;
key_t key;
key = ftok(".",1);
semId = semget(key,1,IPC_CREAT|0666); //获取或创建信号量
union semun seminit;
seminit.val = 0; //初始钥匙的数量
semctl(semId,0,SETVAL,seminit); //初始化信号量
pid = fork();
if(pid > 0){
//拿锁
pGetKey(semId);
printf("this is father!\n");
//把锁放回去
vPutBackKey(semId);
}else if(pid == 0){
printf("this is child!\n");
vPutBackKey(semId);
}else{
printf("fork error!\n");
}
return 0;
}