#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define PERMS S_IRUSR|S_IWUSR
void init_semaphore_struct(struct sembuf *sem,int semnum,
int semop,int semflg)
{
/* 初始话信号灯结构 */
/*信号灯的主要用途是保护临界资源(在一个时刻只被一个进程所拥有).*/
sem->sem_num=semnum;
sem->sem_op=semop;
sem->sem_flg=semflg;
}
/*
struct sembuf
{
short sem_num; // 使用那一个信号
short sem_op; // 进行什么操作
short sem_flg; // 操作的标志
};
*/
int del_semaphore(int semid)
{
/* 信号灯并不随程序的结束而被删除,如果我们没删除的话(将1 改为0)
可以用ipcs 命令查看到信号灯,用ipcrm 可以删除信号灯的
*/
/*
int semctl(int semid,int semnum,int cmd,union semun arg);
semctl 对信号量进行一系列的控制.
semid 是要操作的信号标志,
semnum 是信号的个数,
cmd 是操作的命令.经常用的两个值是:SETVAL(设置信号量的值)和IPC_RMID(删除信号灯).
arg 是一个给cmd 的参数.
*/
#if 1
return semctl(semid,1,IPC_RMID);//删除一个信号灯
#endif
}
/*
int semop(int semid,struct sembuf *spos,int nspos);
semop 是对信号进行操作的函数.
semid 是信号标志,
spos 是一个操作数组表明要进行什么操作,
nspos 表明数组的个数.
如果sem_op 大于0,那么操作将sem_op 加入到信号量的值中,并唤醒等待信号增加的进程.
如果为0,当信号量的值是0 的时候,函数返回,否则阻塞直到信号量的值为0. 如果小于0,
函数判断信号量的值加上这个负值.如果结果为0 唤醒等待信号量为0 的进程,如果小与0
函数阻塞.如果大于0,那么从信号量里面减去这个值并返回..
*/
int main(int argc,char **argv)
{
char buffer[MAX_CANON],*c;
int i,n;
int semid,semop_ret,status;
pid_t childpid;
struct sembuf semwait,semsignal;
if((argc!=2)||((n=atoi(argv[1]))<1))
{
fprintf(stderr,"Usage:%s number\n\a",argv[0]);
exit(1);
}
fprintf(stderr,"pid=%ld\n",getpid());
/* 使用IPC_PRIVATE 表示由系统选择一个关键字来创建 */
/* 创建以后信号灯的初始值为0 */
/*
int semget(key_t key,int nsems,int semflg);
.semget 创建一个信号量.成功时返回信号的ID,
key 是一个关键字,可以是用ftok 创建的也可以是IPC_PRIVATE 表明由系统选用一个关键字.
nsems 表明我们创建的信号个数.
semflg 是创建的权限标志,和我们创建一个文件的标志相同
*/
if((semid=semget(IPC_PRIVATE,1,PERMS))==-1)//创建一个信号
{
fprintf(stderr,"[%d]:Acess Semaphore Error:%s\n\a",
getpid(),strerror(errno));
exit(1);
}
/* semwait 是要求资源的操作(-1) */
init_semaphore_struct(&semwait,0,-1,0);
/* semsignal 是释放资源的操作(+1) */
init_semaphore_struct(&semsignal,0,1,0);
/* 开始的时候有一个系统资源(一个标准错误输出) */
if(semop(semid,&semsignal,1)==-1)
{
fprintf(stderr,"[%d]:Increment Semaphore Error:%s\n\a",
getpid(),strerror(errno));
if(del_semaphore(semid)==-1)
fprintf(stderr,"[%d]:Destroy Semaphore Error:%s\n\a",
getpid(),strerror(errno));
exit(1);
}
/* 创建一个进程链 */
for(i=0;i<n;i++)
{
if(childpid=fork())
break;
else
printf("i=%d,childpid=%d\n",i,childpid);
}
sprintf(buffer,"[i=%d]-->[Process=%d]-->[Parent=%d]-->[Child=%d]\n",i,getpid(),getppid(),childpid);
c=buffer;
/* 这里要求资源,进入原子操作 */
while(((semop_ret=semop(semid,&semwait,1))==-1)&&(errno==EINTR));
if(semop_ret==-1)
{
fprintf(stderr,"[%d]:Decrement Semaphore Error:%s\n\a",
getpid(),strerror(errno));
}
else
{
while(*c!='\0')fputc(*c++,stderr);
/* 原子操作完成,赶快释放资源 */
while(((semop_ret=semop(semid,&semsignal,1))==-1)&&(errno==EINTR));
if(semop_ret==-1)
fprintf(stderr,"[%d]:Increment Semaphore Error:%s\n\a",
getpid(),strerror(errno));
}
/* 不能够在其他进程反问信号灯的时候,我们删除了信号灯 */
while((wait(&status)==-1)&&(errno==EINTR));
/* 信号灯只能够被删除一次的 */
if(i==1)
if(del_semaphore(semid)==-1)
fprintf(stderr,"[%d]:Destroy Semaphore Error:%s\n\a",
getpid(),strerror(errno));
exit(0);
}
[root@localhost sem]# gcc -o semOp semOp.c
[root@localhost sem]# ./semOp 5
pid=22500
i=0,childpid=0
i=1,childpid=0
i=2,childpid=0
i=3,childpid=0
[i=3]-->[Process=22503]-->[Parent=22502]-->[Child=22504]
[i=2]-->[Process=22502]-->[Parent=22501]-->[Child=22503]
[i=1]-->[Process=22501]-->[Parent=22500]-->[Child=22502]
[i=0]-->[Process=22500]-->[Parent=8740]-->[Child=22501]
i=4,childpid=0
[i=4]-->[Process=22504]-->[Parent=22503]-->[Child=22505]
[i=5]-->[Process=22505]-->[Parent=22504]-->[Child=0]
[root@localhost sem]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x02012088 262144 root 666 4 2
0x01012155 294913 root 666 4 1
0x00000000 32931844 root 700 32768 2 dest
0x00000000 32964613 root 700 131072 2 dest
------ Semaphore Arrays --------
key semid owner perms nsems
0x0101fbdd 0 root 600 1
0x16012088 98305 root 666 1
0xde012088 131074 root 666 1
0x0101fa03 163843 root 600 1
0x0b012155 196612 root 666 1
0x6f012155 229381 root 666 1
------ Message Queues --------
key msqid owner perms used-bytes messages
[root@localhost sem]#