IPC一个综合小实践
Posted randyniu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IPC一个综合小实践相关的知识,希望对你有一定的参考价值。
多进程读写共享内存使用信号量进行同步实现链接访问技术功能
1 共享内存相关操作API
2 信号量相关操作API
3 多进程测试框架
4 将上面的内容结合起来
定义共享内存的API操作
//ipc_shm.h #ifndef _IPC_SHM_H_ #define _IPC_SHM_H_ #ifdef __cplusplus extern "C" { #endif int shm_creat(char *shmseedfile, int shmsize, int *shmhdl); int shm_map(int shmhdl,void **mapaddr); int shm_unmap(void *unmapaddr); int shm_delete(int shmhdl); #ifdef __cplusplus } #endif #endif
// ipc_sem.c
#include <stdio.h> #include <errno.h> #include <unistd.h> #include <memory.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/msg.h> #include "ipc_shm.h" //两个全局变量,用来作为标识 int shmflag = 0; int shmkey; int shm_creat(char *shmseedfile, int shmsize, int *shmhdl) { if(shmflag == 0) //判断接口中共享内存key是否已经存在 { shmkey = ftok(shmseedfile, ‘a‘); if (shmkey == -1) { perror("ftok"); return -1; } shmflag = 1; } //创建共享内存 int ret = shmget(shmkey,shmsize,IPC_CREAT | 0666); if (ret == -1) //创建失败 return -1; *shmhdl = ret; return 0; } int shm_map(int shmhdl, void **mapaddr) { void *tempptr = NULL; //连接共享内存 tempptr = (void *)shmat(shmhdl,0,SHM_RND); if ((int)tempptr == -1) //共享内存连接失败 return -1; *mapaddr = tempptr; //导出共享内存首指针 return 0; } int shm_unmap(void *unmapaddr) { int rv; //取消连接共享内存 rv = shmdt(unmapaddr); if (rv == -1) //取消连接失败 return -1; return 0; } int shm_delete(int shmhdl) { int rv; //删除共享内存 rv = shmctl(shmhdl,IPC_RMID, NULL); if(rv < 0) //删除共享内存失败 return -1; return 0; }
//ipc_shm.h
#ifndef _IPC_SEM_H_ #define _IPC_SEM_H_ #ifdef __cplusplus extern "C" { #endif int sem_creat(int key, int *semid); int sem_delete(int key); int sem_open(int key, int *semid); int sem_setval(int semid, int val); int sem_getval(int semid, int *val); int sem_p(int semid); int sem_v(int semid); #ifdef __cplusplus } #endif #endif
// ipc_shm.c
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ipc_sem.h" //用来操作信号量值的联合体 union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ }; // 成功返回0,失败返回其他 // 如果没有就创建信号量,并且设置信号,如果有就报错,下次调用sem_open函数打开信号量,同时也设置信号量。 int sem_creat(int key, int *semid) { if (semid == NULL) { printf("sem_creat() Param Err.\n"); return -1; } int ret = semget(key, 1, 0666| IPC_CREAT | IPC_EXCL); if (ret == -1) { if (errno == EEXIST) { printf("semget() EXIST Err.\n"); return -1; } } *semid = ret; ret = sem_setval(*semid, 1); if (ret != 0) { printf("sem_setval() Err : %d\n", ret); return ret; } return 0; } int sem_delete(int key) { int semid; int ret = sem_open(key, &semid); if(ret < 0) { return -1; } ret = semctl(semid, IPC_RMID, 0); if(ret < 0) { return -1; } return 0; } int sem_open(int key, int *semid) { if (semid == NULL) { printf("sem_creat() Param Err.\n"); return -1; } int ret = semget(key, 0, 0); if (ret == -1) { printf("sem_open() Err:%d\n", errno); return ret; } *semid = ret; return 0; } int sem_setval(int semid, int val) { union semun su; su.val = val; return semctl(semid, 0, SETVAL, su); } int sem_getval(int semid, int *val) { int ret = semctl(semid, 0, GETVAL); *val = ret; return 0; } //信号量P操作时候,需要传递好几个信息给linux内核,所以linux内核定义了一个结构 //操作信号量集的下标 0 //执行什么操作 -1 +1 //按照什么策略执行操作 0 UNDO NOWAITing int sem_p(int semid) { struct sembuf buf = {0, -1, 0}; return semop(semid, &buf, 1); } int sem_v(int semid) { struct sembuf buf = {0, 1, 0}; return semop(semid, &buf, 1); }
#include <sys/types.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/wait.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "ipc_sem.h" #include "ipc_shm.h" int g_key = 0x1234; // 进程调用的执行函数 int doServeice() { //开始使用信号量来创造临界区 int semid = 0; sem_open(g_key, &semid); sem_p(semid); //临界区开始 int shmhdl = 0; int ret = shm_creat(".", 0, &shmhdl); if(ret!=0) { return ret; } int *addr = NULL; ret =shm_map(shmhdl, (void **)&addr); if(ret!=0) { return ret; } // 进程访问数+1 *((int *)addr) += 1; //统计总共访问的次数。 int ncount = *((int *)addr); printf("ncount: %d\n", ncount); ret =shm_unmap(addr); //sleep(1); sem_v(semid); //临界区开始 } int main() { int procnum; printf("输入创建子进程的个数 : \n"); scanf("%d", &procnum); int loopnum; printf("输入每个子进程测试多少圈 :\n"); scanf("%d", &loopnum); //共享内存创建 int shmhdl = 0; int ret = shm_creat(".", sizeof(int), &shmhdl); if (ret != 0) { printf("shm_creat() Err.\n"); return ret; } //共享内存创建成功 //信号量的创建 int semid = 0; ret = sem_creat(g_key, &semid); if (ret != 0) { printf("sem_creat() Err. Try Again.\n"); if (errno == EEXIST) { ret = sem_open(g_key, &semid); if (ret != 0) { printf("Failed Again!\n"); return ret; } } else { return ret; } } int val = 0; ret = sem_getval(semid, &val); if (ret != 0 ) { printf("sem_getval() Err.\n"); return ret; } printf("sem val: %d\n", val); getchar(); pid_t pid; for (int i=0; i<procnum; i++) { pid = fork(); //有几个fork就有几个子进程 if (pid == 0) { for (int j=0; j<loopnum; j ++) { int rev = doServeice(); if(rev!=0) { return -1; } } exit(0); } } //用来等待子进程的结束,防止僵尸进程的产生, 为了不让父进程死亡,采用这种方式 while(1) { if((pid = waitpid(-1, NULL, WNOHANG)) > 0) { printf("子进程正常退出:%d\n", pid); } else { if(pid == -1) { if(errno == EINTR) continue; else break; } } } // 释放资源 shm_delete(shmhdl); sem_delete(g_key); return 0; }
以上是关于IPC一个综合小实践的主要内容,如果未能解决你的问题,请参考以下文章