1.定义
信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。这里主要讨论二进制信号量。
2.P、V操作
P、V操作是定义在信号量上的S上的两个操作
P(S)
a、 S:=S-1;
b、若S>=0,则调用P(S)的进程继续运行;
c、若S<0,则调用P(S)的进程被阻塞,并把它插入到等待信号量S的阻塞队列中。
V(S)
a、S:=S+1;
b、若S>0,则调用V(S)的进程继续运行;
c、若S<=0,从等待信号量S的阻塞队列中唤醒头一个进程,然后调用V(S)的进程继续运
3.函数
int semget(key_t key,int num_sems,int sem_flags);
作用:创建一个新信号量或取得一个已有信号量的键
返回值:成功返回信号量ID,出错返回-1。
key_t key:为整型值,用户可以自己设定。
int num_sems:初始化信号量的个数。
int sem_flags:信号量的创建方式或权限。有IPC_CREAT,IPC_EXCL。
IPC_CREAT如果信号量不存在,则创建一个信号量,否则获取。
IPC_EXCL只有信号量不存在的时候,新的信号量才建立,否则就产生错误。
ipcs -s 查看信号量是否创建成功
ipcrm -s simid 删除指定的信号量
int semop(int semid,struct *sem_ops , size_t num_sem_ops)
作用:用户改变信号量的值,即使用资源还是释放资源的使用权。
返回值:成功返回0,失败返回-1。
int semid:信号量的标识码,即senget()函数的返回值。
struct *sem_ops:指向结构体数组的指针。
struct sembuf
{
struct short sem_num;//在信号量集中的编号,第一个为0
short sem_op;//对信号量的操作
short sem_flg;//通常被设置为SEM_UNDO,程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
};
size_t num_sem_ops:nsops:操作结构的数量,恒大于或等于1。
int semctl(int sem_id, int sem_num, int command,…….);
作用:控制信号量信息。
返回值:成功返回0,失败返回-1。
int sem_id: 信号量的标志码(ID),也就是semget()函数的返回值;
int sem_num:操作信号在信号集中的编号。从0开始。
int command: 命令,表示要进行的操作。
参数command中可以使用的命令如下:
IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID将信号量集从内存中删除。
GETALL用于读取信号量集中的所有信号量的值。
GETNCNT返回正在等待资源的进程数目。
GETPID返回最后一个执行semop操作的进程的PID。
GETVAL返回信号量集中的一个单个的信号量的值。
GETZCNT返回这在等待完全空闲的资源的进程数目。
SETALL设置信号量集中的所有的信号量的值。
SETVAL设置信号量集中的一个单独的信号量的值。
若有第四个参数,它是一个联合体结构:
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arrary;
};
代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/sem.h>
#include<fcntl.h>
int semid;
union semun //semctl的第四个参数,它是一个联合体
{
int val;
};
//由进程调用,确保获取到信号量集
void sem_get(int key,int val)
{
semid=semget((key_t)key,1,0666);//semid是信号量的标志码
if(semid==-1)//没有此信号量集
{
semid=semget((key_t)key,1,0666|IPC_CREAT);//在内核中创建信号量集
assert(semid!=-1);
union semun v; //semctl的第四个参数是一个联合体结构
v.val=val;
semctl(semid,0,SETVAL,v);
}
}
//p操作
void sem_p()
{
struct sembuf op;//semop的第二个参数是指向结构体数组的指针
op.sem_num=0;
op.sem_op=-1;
op.sem_flg=SEM_UNDO;//若进程没有释放该信号量,则操作系统自动释放
semop(semid,&op,1);
}
//v操作
void sem_v()
{
struct sembuf op;
op.sem_num=0;
op.sem_op=1;
op.sem_flg=SEM_UNDO;
semop(semid,&op,1);
}
void sem_del()
{
semctl(semid,0,IPC_RMID,NULL);
}
mainA.c
#include"sem.h"
void main()
{
int fd=open("FIFO",O_WRONLY);
assert(fd!=-1);
sem_get(1234,0);
while(1)
{
printf("please input:");
fflush(stdout);
char buff[128]={0};
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
write(fd,buff,strlen(buff));
sem_v();
}
}
mainB.c
#include"sem.h"
void main()
{
int fd=open("FIFO",O_RDONLY);
assert(fd!=-1);
sem_get(1234,0);
while(1)
{
sem_p();
printf("B proc start\n");
char buff[128]={0};
read(fd,buff,127);
printf("B ::%s\n",buff);
}
}
“`