信号量含义:他是一个计数器,用于进程间的互斥与同步,并不用于存储进程间的通信的数据。
特点:
1.信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
2.信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
3.每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
4.支持信号量组。
相关的API
1创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
int semget(key_t key, int num_sems, int sem_flags);
当semget创建新的信号量集合时,必须指定集合中信号量的个数(即num_sems),通常为1; 如果是引用一个现有的集合,则将num_sems指定为 0 。
第二个参数为IPC_CREAT 时 要或(|)上相应的权限。如果是引用为 指定为 0。
2 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5int semop(int semid, struct sembuf semoparray[], size_t numops);
第二个参数为结构体,不用自己定义,直接引用。
struct sembuf
{
short sem_num; // 信号量组中对应的序号,0~sem_nums-1
short sem_op; // 信号量值在一次操作中的改变量
short sem_flg; // IPC_NOWAIT, SEM_UNDO
}
其中 sem_op 是一次操作中的信号量的改变量:
若sem_op > 0,表示进程释放相应的资源数,将 sem_op 的值加到信号量的值上。如果有进程正在休眠等待此信号量,则换行它们。
若sem_op < 0,请求 sem_op 的绝对值的资源。
sem_flg 通常为 SEM_UNDO (没有资源时等待)。
第三个参数通常为1,对一个信号量进行操作。
3 // 控制信号量的相关信息
int semctl(int semid, int sem_num, int cmd, …);
在semctl函数中的 cmd 有多种,这里就说两个常用的:
SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。必须自己定义一个联合体,结构如下
union semun
{
int val; /for SETVAL/ 信号量的值
struct semid_ds *buf;
unsigned short *array;
};
IPC_RMID:删除一个信号量集合。如果不删除信号量,它将继续在系统中存在,即使程序已经退出,它可能在你下次运行此程序时引发问题,而且信号量是一种有限的资源。
#include<stdlib.h>
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
union semun initsem;
int semid;
int sem_creat()
{
key_t key;
key=ftok(".",1);
semid=semget(key ,1,IPC_CREAT|0666);
if(semid==-1)
{
perror("why");
return -1;
}
}
int sem_p()
{
struct sembuf sops;
sops.sem_num=0;
sops.sem_op=-1;
sops.sem_flg= SEM_UNDO;
if(semop(semid, &sops, 1)==-1)
{
printf("sem_p failed\n");
exit(-1);
}
}
int sem_v()
{
struct sembuf sops;
sops.sem_num=0;
sops.sem_op=1;
sops.sem_flg= SEM_UNDO;
if(semop(semid, &sops, 1)==-1)
{
printf("sem_v failed\n");
exit(-1);
}
}
int main()
{ pid_t pid ;
sem_creat();
initsem.val=0;
semctl(semid, 0, SETVAL,initsem);
pid=fork();
if(pid==0)
{
printf("i am a child\n");
sem_v();
int a=semctl(semid,0,GETVAL,initsem);
printf("child a=%d\n",a);
}
else if(pid>0)
{
sem_p();
int a=semctl(semid,0,GETVAL,initsem);
printf("a=%d\n",a);
printf("i am a father\n");
sem_v();
a=semctl(semid,0,GETVAL,initsem);
printf("a=%d\n",a);
}
else{
printf("fork failed\n");
exit(-1);
}
return 0;
}