Chinaunix首页 | 论坛 | 博客
  • 博客访问: 441341
  • 博文数量: 113
  • 博客积分: 446
  • 博客等级: 下士
  • 技术积分: 1229
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-09 16:01
个人简介

Let's go!!!!!

文章分类

全部博文(113)

文章存档

2019年(5)

2018年(4)

2017年(9)

2016年(5)

2015年(39)

2014年(6)

2013年(28)

2012年(17)

分类: LINUX

2012-12-15 09:43:55

    信号量是一个可被多个进程共享的数据结构。信号量通常是在多个进程访问一个临界资源的情况下,用于同步各个进程之间的操作,避免死锁问题。当同步访问一个资源时,可以设置一个信号量,其初始值设可用资源的数目。每当进程想要获取资源时,都要检测相关的信号量。信号量大于0表明资源可用,当获取对资源的访问权限时,将信号量减一。为保证程序运行的正确性,对信号量的检测和减操作都必须是原子性的。如果检测到信号量值为0,则表明资源不可用看,请求进程必须等待;当一个进程结束时,对与该进程对应的信号量加一,表明此进程归还对此资源的使用。一旦一种资源被归还,所有等待该资源的进程都会受到系统的通知。为控制对单一资源的使用,取0(资源在使用中),1(资源空闲中)两个信号量,通常称为二元信号量。信号量集是信号量的集合。
 
 
信号量集数据结构
struct  semid_ds{
struct ipc_perm sem_perm;        //操作存取访问权限结构
struct sem      *sem_base;       //指向信号量集中第一个信号量
ushort_t        sem_nsems;       //信号量集中信号量的个数
time_t          sem_otime;       //最后的semop时间
long            sem_padl;        //为time_t扩展所保留的空间
time_t          sem_ctime;       //最后一册改变的时间
long            sem_pad2;        //time_t扩展
long            sem_pad3[4];     //保留区   
};
struct sem{
ushort semval;      //信号量的值
pid_t  sempid;      //最后操作的pid;
ushort semncnt;     //等待等待信号量递增的进程个数
ushort semzcnt;     //等待信号量变为0的进程个数
};
函数原型:int semget(key_t key,int nsems,int semflg)  生成一个信号量集。
key:键值
nsems:信号量集中的信号量数目
semflg:信号量创建条件 IPC_CREAT、IPC_EXCL

#include
#include
#include
#include
#include
#include
#define exit_err(str)  do{perror(str);}while(0);
#define num 255
int main()
{
int sem1,sem2,sem3;
key_t key;
key=ftok(".",'S');
if((sem1=semget(IPC_PRIVATE,3,IPC_CREAT|0666))==-1)       //创建一个信号量集,有3个信号量
exit_err("semget sem1 error");
printf("sem1=%d\n",sem1);
if((sem2=semget(key,3,IPC_CREAT|IPC_EXCL|0666))==-1)
exit_err("semget sem2 error");
printf("sem2=%d\n",sem2);
if((sem3=semget(key,3,IPC_CREAT|0666))==-1)
exit_err("semget sem3 error");
printf("sem3=%d\n",sem3);
return 0;
}

函数原型:int semctl(int semid,int semnum,int cmd,union semun arg)  控制信号量
semid;为semget的返回值
semnum:集合中信号量的个数
arg:其类型是senum的联合(union),其值决定于cmd的值,可以是一个整数,可以是指semid_ds数据结构,也可是一个短型数组的基地址。
cmd:
IPC_STAT:返回信号量集semid_ds数据结构,存储在由semctl第四个参数的一个用户生成的结构中
IPC_SET:与IPC_STAT相反
IPC_RMID:删除信号量集
GETALL:返回信号集中所有信号量的当前值
SETALL:与GETALL相反
GETVAL:返回给别信号量的当前值
SETVAL:与GETVAL相反
GETPID:返回semid_ds的sem_perm子结构中包含的进程ID
GETNCNT:返回等待semnum所指明的信号量地址的进程数
GETZCNT:返回等待semnum所指明的信号量变为0的进程数
#include
#include
#include
#include
#include
#include
#define NS 3
#define NUM 255
union senun{
int val;
struct semid_ds *buf;
ushort *array;
}arg;
int main()
{
int sem_id,sem_value,i;
key_t key;
struct semid_ds sem_buf;
static ushort sem_array[NS]={3,1,4};
key=ftok("/dev/null",NUM);
if((sem_id=semget(key,NS,IPC_CREAT|0600))==-1)                //创建信号量集
{
perror("semget error");
exit(1);
}
printf("sem_id=%d\n",sem_id);
arg.buf=&sem_buf;
if(semctl(sem_id,3,IPC_STAT,arg)==-1)                         
{
perror("semctl error");
exit(1);
}
printf("number of semaphores %d,last modify time %s",sem_buf.sem_nsems,ctime(&sem_buf.sem_ctime));
arg.array=sem_array;
if(semctl(sem_id,0,SETALL,arg)==-1)                        //设置信号量集中信号量的初始值
{
perror("semctl error");
exit(1);
}
for(i=0;i{
if((sem_value=semctl(sem_id,i,GETVAL,0))==-1)           //获取每个信号量的值,打印
{
perror("semctl error");
exit(0);
}
printf("semaphore %d has value of %d\n",i,sem_value);
}
arg.val=10;
semctl(sem_id,1,SETVAL,arg.val);                         //改变一个信号量的值
for(i=0;i{
if((sem_value=semctl(sem_id,i,GETVAL,0))==-1)
{
perror("semctl error");
exit(0);
}
printf("semaphore %d has value of %d\n",i,sem_value);
}
semctl(sem_id,0,IPC_RMID,(struct msquid_ds *)0);
return 0;
}

函数原型:int semop(int semid,struct sembuf *sops,size_t nsops)   信号量操作
semid:为semget的返回值
sops:是一指向个操作数组的基址的指针,这个数组中的每个操作都将用于semid对应的信号量上
nsops:指明操作数组中包含的元素个数
struct sembuf{
ushort sem_num;      //信号量编号
short  sem_op;       //信号操作
short  sem_flg;      //操作标识
};
semop=1,表明对信号量进行加一操作
semop=0,表明对信号量的当前值进行是否为0的测试
semop=-1,表明对信号量进行减一操作
sem_flag:
IPC_NOWAIT:对信号量的操作(比如递减或测试是否为0)不能执行的情况下,立刻返回。
IPC_UNDO:允许一个被阻塞的操作失败时撤销操作
示例程序:
程序中使用两个信号量来协同两个进程的并发,生产者和消费者。生产者产生一个整型值,保存在一个非共享的文件中。消费者进程的动作时一旦产生一个新值,就从
文件中读取它,并打印在屏幕上。生产者使用信号量以防止在消费者进程之前覆盖一个先前的存入文件的值,消费者极进程使用信号量是为了阻止对一个值多次检索。
#include
#include
#include
#include
#include
#include
#define exit_err(str) do{perror(str);exit(1);}while(0);
#define NUM 255
#define BUFFER "./buffer"
 union semun{
int val;
struct semid_ds *buf;
ushort *array;
};
int main()
{
FILE *fp;
struct sembuf acquire={0,-1,SEM_UNDO},release={0,1,SEM_UNDO};             
pid_t pid;
key_t key;
ushort start_val[2]={1,0};
int semid,producer,i,n,j=9;
union semun arg;
enum{READ,MADE};
if((key=ftok("/dev/null",NUM))==-1)
exit_err("ftok error");
if((semid=semget(key,2,IPC_CREAT|0666))==-1)             //创建一个信号量集
exit_err("semget error");
producer=1;
arg.array=start_val;
if(semctl(semid,0,SETALL,arg)==-1)                       //对信号量集中的信号量值初始化,1表明生产者可生产,0表明消费者不可消费
exit_err("semid error");
srand((int)time(0));
do{
switch(producer)
{
case 1:
n=rand()%99+1;
printf("A.The number [%2d] generated by producer\n",n);
acquire.sem_num=READ;                                  //对第一个信号量操作
if(semop(semid,&acquire,1)==-1)                        //p操作
exit_err("semop error");
if((fp=fopen(BUFFER,"w"))==NULL)
exit_err("fopen error");
fprintf(fp,"%d\n",n);
fclose(fp);
release.sem_num=MADE;                                  //对第二个信号量操作
printf("B.The number [%2d] deposited by producer\n",n);
if(semop(semid,&release,1)==-1)                        //v操作
exit_err("semop error");
producer=2;
break;
case 2:
acquire.sem_num=MADE;                                 //对第二个信号量操作
if(semop(semid,&acquire,1)==-1)                       //p操作
exit_err("semop error");
if((fp=fopen(BUFFER,"r"))==NULL)
exit_err("fopen error");
fscanf(fp,"%d",&n);
fclose(fp);
release.sem_num=READ;                                 //对第一个信号量操作
if(semop(semid,&release,1)==-1)                       //v操作
exit_err("semop error");
printf("C.The number [%2d] obtained by consumer\n",n);
producer=1;
break;
}
}while(j--);
semctl(semid,0,IPC_RMDI,0);                           //删除信号量集
return 0;
}
阅读(1794) | 评论(1) | 转发(0) |
0

上一篇:rand() srand()

下一篇:TCP UDP通讯模型

给主人留下些什么吧!~~

heiniuwuyuhang2015-04-19 17:00:59

获得信号量的值那里不对