12.1 共享内存、信号量函数封装、多进程操作共享内存

时间:2022-10-31 14:46:02

   共享内存函数封装:

  1 #include <unistd.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <sys/mman.h>
  6 #include <sys/ipc.h>
  7 #include <sys/shm.h>
  8 #include <sys/sem.h>
  9 
 10 #include <stdlib.h>
 11 #include <stdio.h>
 12 #include <errno.h>
 13 #include <string.h>
 14 
 15 #include <sys/ipc.h>
 16 #include <sys/sem.h>
 17 #include "myipc_sem.h"
 18 
 19 
 20 union semun {
 21 int              val;    /* Value for SETVAL */
 22 struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
 23 unsigned short  *array;  /* Array for GETALL, SETALL */
 24 struct seminfo  *__buf;  /* Buffer for IPC_INFO
 25                            (Linux specific) */
 26 };
 27 
 28 //@返回值 0 正确 其他错误
 29 int sem_creat(int key, int *semid)
 30 {
 31     int     ret = 0;
 32     //int     tmpsemid = 0;
 33     
 34     if (semid == NULL)
 35     {
 36         ret = SEMERR_PARAM;
 37         printf("func sem_creat() err:%d\n", ret);
 38         return ret;
 39     }
 40     ret = semget(key, 1, 0666| IPC_CREAT | IPC_EXCL); 
 41     if (ret == -1)
 42     {
 43             ret = errno;
 44             //perror("semget");
 45             if (errno == EEXIST) 
 46             {
 47                 ret = SEMERR_EEXIST;
 48                 printf("func sem_creat() 检测到信号量集已经存在:%d\n", ret);
 49                 return ret;
 50             }
 51     }
 52     *semid = ret;
 53     
 54     ret = sem_setval(*semid, 1);
 55     if (ret != 0)
 56     {
 57         printf("func sem_setval() err:%d\n", ret);
 58         return ret;
 59     }
 60     ret = 0;
 61     return ret;
 62 }   
 63 
 64 int sem_open(int key, int *semid)
 65 {
 66     int ret = 0;
 67     
 68     if (semid == NULL)
 69     {
 70         ret = SEMERR_PARAM;
 71         printf("func sem_open() err:%d\n", ret);
 72         return ret;
 73     }
 74     
 75     ret = semget(key, 0, 0); 
 76     if (ret == -1)
 77     {
 78             ret = errno;
 79             printf("func sem_open() 失败:%d\n", ret);
 80             return ret;    
 81     }
 82     *semid = ret;
 83     ret = 0;
 84     return ret;
 85 }  
 86 
 87 int sem_setval(int semid, int val)
 88 {
 89     int ret = 0;
 90     union semun su;
 91     su.val = val;
 92     ret = semctl(semid, 0,  SETVAL, su);
 93     return ret;
 94 }
 95 
 96 /*
 97 int sem_getval(int semid, int *val)
 98 {
 99     int ret = 0;
100     int tmpval;
101     if (val == NULL)
102     {
103         ret = SEMERR_PARAM;
104         printf("func sem_getval() err:%d\n", ret);
105         return ret;
106     }
107     union semun su;
108     tmpval = su.val ;
109     ret = semctl(semid, 0, GETVAL, su);
110     *val = tmpval  ;
111     printf("val:%d\n", tmpval);
112     return ret;
113 }
114 */
115 int sem_getval(int semid, int *myval)
116 {
117     int ret = 0;
118     int val;
119     union semun su;
120     val = su.val ;
121     //信号量 计数值
122     ret = semctl(semid, 0, GETVAL, su);
123     //printf("val:%d\n", val);
124     
125     *myval = ret;
126     ret = 0;
127     return ret;
128 }
129 
130 //信号量p操作时候,需要传递好几个信息给linux内核
131 //所以linux内核定义了一个结构
132 //我要操作信号量集的下标 0
133 //我要执行什么操作 -1 +1
134 //我按照什么策略执行操作 0  UNDO NOWAITing
135 int sem_p(int semid)
136 {
137     struct sembuf buf = {0, -1, 0};
138     int ret = 0;
139     ret = semop(semid, &buf, 1);
140     return ret;
141 }
142 
143 int sem_v(int semid)
144 {
145     struct sembuf buf = {0, 1, 0};
146     int ret = 0;
147     ret = semop(semid, &buf, 1);
148     return ret;
149 }

 

  信号量函数封装:

 1 #define    _OS_LINUX_
 2 
 3 #if defined _OS_LINUX_
 4 #include <stdio.h>
 5 #include <errno.h>
 6 #include <unistd.h>
 7 #include <memory.h>
 8 #include <sys/ipc.h>
 9 #include <sys/shm.h>
10 #include <sys/sem.h>
11 #include <sys/msg.h>
12 #include "myipc_shm.h" 
13 
14 #endif
15 
16 int shmflag = 0;
17 int shmkey;
18 
19 /***********************************************************************
20   功能描述:    创建共享内存
21   参数说明:    shmname  [in]  是共享内存名,系统中唯一标志
22                 shmsize  [in]  是要创建的共享内存的大小;
23                 shmhdl   [out] 共享内存的句柄.
24   返回值:      返回0函数执行成功;非0返回错误码
25 ************************************************************************/
26 int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl)
27 {
28     if(shmflag == 0)            //判断接口*享内存key是否已经存在
29     {
30         shmkey = ftok(shmseedfile, 'c');
31         if (shmkey == -1)
32         {
33             perror("ftok");
34             return -1;
35         }
36             
37         shmflag = 1;
38     }
39     
40     //创建共享内存
41     *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666);
42     if (*shmhdl == -1)            //创建失败
43         return -2;
44     return 0;
45 
46 }
47 /***********************************************************************
48   功能描述:    关联共享内存
49   参数说明:    shmhdl    [in]  共享的句柄
50                 mapaddr [out] 共享内存首地址
51   返回值:      返回0函数执行成功;非0返回错误码
52 ************************************************************************/
53 int
54 IPC_MapShm(int  shmhdl, void  **mapaddr)
55 {
56     void *tempptr = NULL;
57 
58     //连接共享内存
59     tempptr = (void *)shmat(shmhdl,0,SHM_RND);
60     if ((int)tempptr == -1)        //共享内存连接失败
61         return -1;
62     *mapaddr = tempptr;            //导出共享内存首指针
63 
64     return 0;
65 }
66 /***********************************************************************
67   功能描述:    取消共享内存关联
68   参数说明:    unmapaddr   [in] 共享内存首地址
69   返回值:      返回0函数执行成功;非0返回错误码
70 ************************************************************************/
71 int IPC_UnMapShm(void *unmapaddr)
72 {
73     int  rv;
74     //取消连接共享内存 
75     rv = shmdt((char *)unmapaddr);
76     if (rv == -1)            //取消连接失败
77         return -1;
78 
79     return 0;
80 }
81 /***********************************************************************
82   功能描述:    删除共享内存
83   参数说明:    shmhdl    [in]  共享的句柄
84   返回值:      返回0函数执行成功;非0返回错误码
85 ************************************************************************/
86 int IPC_DelShm(int shmhdl)
87 {
88     int  rv;
89     //删除共享内存
90     rv = shmctl(shmhdl,IPC_RMID,NULL);
91     if(rv < 0)                //删除共享内存失败
92         return -1;
93     return 0;
94 }

 多进程操作共享内存:

  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <string.h>
  7 
  8 #include <signal.h>
  9 #include <errno.h>
 10 #include <signal.h>
 11 #include <sys/wait.h>
 12 
 13 #include "myipc_sem.h"
 14 #include "myipc_shm.h"
 15 
 16 int g_key = 0x3333;
 17 
 18 void TestFunc(int loopnum)
 19 {
 20     printf("loopnum:%d\n", loopnum);
 21     
 22     int ncount = 0;
 23     int ret = 0;
 24     int shmhdl = 0;
 25     int *addr = NULL;
 26     
 27     int semid = 0;
 28     sem_open(g_key, &semid);
 29 
 30 
 31      sem_p(semid); //临界区开始
 32     //
 33         ret = IPC_CreatShm(".", 0, &shmhdl);
 34         
 35         ret =IPC_MapShm(shmhdl, (void **)&addr);
 36         *((int *)addr) =  *((int *)addr)  + 1;
 37         ncount = *((int *)addr);
 38         printf("ncount:%d\n", ncount);
 39         //addr[0] = addr[0] +1;
 40         ret =IPC_UnMapShm(addr);
 41         sleep(2);
 42         
 43     sem_v(semid);  //临界区开始
 44     //
 45     printf("进程正常退出:%d\n", getpid());
 46 }    
 47 
 48 int main(void )
 49 {
 50     int res;
 51     int procnum=10;
 52     int loopnum = 100;
 53 
 54 
 55     int  i=0,j = 0;
 56 
 57     printf("请输入要创建子进程的个数 : \n");
 58     scanf("%d", &procnum);
 59 
 60     printf("请输入让每个子进程测试多少次 :\n");
 61     scanf("%d", &loopnum);
 62     
 63     //共享内存创建
 64     int        ret = 0;
 65     int     shmhdl = 0;
 66     ret = IPC_CreatShm(".", sizeof(int), &shmhdl);
 67     if (ret != 0)
 68     {
 69         printf("func IPC_CreatShm() err:%d \n", ret);
 70         return ret;
 71     }
 72     
 73     
 74     //信号量的创建
 75      int      semid = 0;
 76     ret = sem_creat(g_key, &semid);
 77     if (ret != 0)
 78     {
 79         printf("func sem_creat() err:%d,重新按照open打开信号量 \n", ret);
 80         if (ret == SEMERR_EEXIST)
 81         {
 82             ret = sem_open(g_key, &semid);
 83             if (ret != 0)
 84             {
 85                 printf("按照打开的方式,重新获取sem失败:%d \n", ret);
 86                 return ret;
 87             }
 88         }
 89         else
 90         {
 91             return ret;
 92         }
 93         
 94     }
 95     
 96     int  val = 0;
 97     ret = sem_getval(semid, &val);
 98     if (ret != 0 )
 99     {
100         printf("func sem_getval() err:%d \n", ret);
101         return ret;
102     }
103     printf("sem val:%d\n", val);
104     getchar();
105 
106     pid_t pid;
107 
108     for (i=0; i<procnum; i++)
109     {
110         pid = fork();  //有几个fork就有几个子进程
111         if (pid == 0)
112         {
113             for (j=0; j<loopnum; j ++)
114             {
115                 TestFunc(j);
116             }
117             exit(0);
118         }
119 
120     }
121 
122     //让所有的子进程退出 父进程才退出
123 
124 /*
125       while(1)
126       {
127           res = wait(NULL);//
128           if(res==-1)
129           {
130               if(errno==EINTR) //若阻塞中有别的信号中断
131               {
132                   continue;
133               }
134               break;
135           }
136       }
137       */
138       
139       int mypid = 0;
140       while ( (mypid= waitpid(-1, NULL, WNOHANG)) > 0)
141       {
142           //printf("退出的子进程pid为:mypid:%d \n", mypid);
143           ;
144       }
145 
146 
147     printf("父进程退出 hello...\n");
148     return 0;
149 }