一个包含了信号、信号量、共享内存的事例(转)
一个包含了信号、信号量、共享内存的例子(转)
一个包含了信号、信号量、共享内存的例子(转)
#include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #define SHMKEY1 (key_t)0x10 #define SHMKEY2 (key_t)0x15 #define SEMKEY (key_t)0x20 #define SIZ 5*BUFSIZ #define IFLAGS (IPC_CREAT|IPC_EXCL) #define ERR ((struct databuf*)-1) //p1,v1是针对第一个信号进行的操作 struct sembuf p1 = {0, -1, 0}; struct sembuf v1 = {0, 1, 0}; //p2,v1是针对第二个信号进行的操作 struct sembuf p2 = {1, -1, 0}; struct sembuf v2 = {1, 1, 0}; //表示两个内存共享区和一个信号量集合 static int shmid1, shmid2, semid; //作为暂时存放数据的结构体 struct databuf { int d_nread; char d_buf[SIZ]; }; void fatal(char *mes) { perror(mes); exit (1); } /**创建两个共享内存,并且分别shmat给两个参数*/ void getshm (struct databuf **p1, struct databuf **p2) { //创建共享内存 if ((shmid1=shmget(SHMKEY1, sizeof(struct databuf), 0600|IFLAGS)) < 0) { fatal ("shmget"); } if ((shmid2=shmget(SHMKEY2, sizeof(struct databuf), 0600|IFLAGS)) < 0) { fatal ("shmget"); } //映射 if ((*p1=(struct databuf*)(shmat(shmid1, 0, 0))) == ERR) { fatal("shmat"); } if((*p2=(struct databuf*)(shmat(shmid2, 0, 0))) == ERR) { fatal("shmat"); } } int getsem() { //获取一个长度为2的信号量集合; if ((semid=semget(SEMKEY, 2, 0600|IFLAGS)) < 0) { fatal("segmet"); } //初始化信号量,假定第一个信号灯没有资源 if (semctl(semid, 0, SETVAL, 0) < 0) { fatal ("semctl"); } //第二个有信息,如果两个信号都没有资源,将会出现死锁 //书上该处有问题 if (semctl(semid, 1, SETVAL, 1) < 0) { fatal ("semctl"); } return (semid); } //回收共享两个内存区和一个信号量集合 void myremove() { if (shmctl(shmid1, IPC_RMID, NULL) < 0) { fatal("shmctl"); } if (shmctl(shmid2, IPC_RMID, NULL) < 0) { fatal("shmctl"); } if (semctl(semid, 0, IPC_RMID, NULL) < 0) fatal("semctl"); exit(0); } void reader(int semid, struct databuf *buf1, struct databuf *buf2) { for(;;) { unsigned short val= semctl(semid,0,GETVAL,null); if(val<=0) { semop(semid,&v1,1); } else{ //申请第一个信号灯资源 semop(semid, &p1, 1) } //从键盘读入数据,放在buf1->d_buf, //read第一个参数是文件描述符,其中0表示从终端输入:如键盘 buf1->d_nread = read(0, buf1->d_buf, SIZ); //v操作,释放第一个信号灯资源 semop(semid, &v1, 1); //p操作,申请第二个信号灯资源,若没有资源,则阻塞进程直到有资源. semop(semid, &p2, 1); buf2->d_nread = read(0, buf2->d_buf, SIZ); //v操作,释放第二个信号灯资源 semop(semid, &v2, 1); } } void writer(int semid, struct databuf *buf1, struct databuf *buf2) { for(;;) { //p操作,等待第一个信号的资源 semop(semid, &p1, 1); //1代表输出到屏幕 write(1, buf1->d_buf, buf1->d_nread); //释放第一个信号灯资源 semop(semid, &v1, 1); //p操作,申请第二个信号灯资源,若没有资源,则阻塞进程直到有资源. semop(semid, &p2, 1); write(1, buf2->d_buf, buf2->d_nread); semop(semid, &v2, 1); } } int main() { int semid, pid; struct databuf *buf1, *buf2; semid = getsem(); getshm (&buf1, &buf2); switch(pid=fork()) { case -1: fatal("fork"); break; case 0: writer(semid, buf1, buf2); break; default: //在主进程中把中断程序的ctrl+c和myremove函数建立联系, //来回收系统资源:共享内存区,信号量. signal (SIGINT, myremove); reader(semid, buf1, buf2); break; } exit(0); }