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


       共享内存函数封装:

      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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", ncount);
     39         //addr[0] = addr[0] +1;
     40         ret =IPC_UnMapShm(addr);
     41         sleep(2);
     42         
     43     sem_v(semid);  //临界区开始
     44     //
     45     printf("进程正常退出:%d
    ", 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("请输入要创建子进程的个数 : 
    ");
     58     scanf("%d", &procnum);
     59 
     60     printf("请输入让每个子进程测试多少次 :
    ");
     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 
    ", 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打开信号量 
    ", ret);
     80         if (ret == SEMERR_EEXIST)
     81         {
     82             ret = sem_open(g_key, &semid);
     83             if (ret != 0)
     84             {
     85                 printf("按照打开的方式,重新获取sem失败:%d 
    ", 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 
    ", ret);
    101         return ret;
    102     }
    103     printf("sem val:%d
    ", 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 
    ", mypid);
    143           ;
    144       }
    145 
    146 
    147     printf("父进程退出 hello...
    ");
    148     return 0;
    149 }
  • 相关阅读:
    (30)导入时如何定制spring-boot依赖项的版本【转载】【从零开始学Spring Boot】
    (29)Spring boot 文件上传(多文件上传)【从零开始学Spring Boot】
    (28)SpringBoot启动时的Banner设置【从零开始学Spring Boot】
    POSIX 消息队列相关问题
    linux系统的7种运行级别
    如何判断是否开启超线程
    (26)改变自动扫描的包【从零开始学Spring Boot】
    (24)Spring Boot环境变量读取和属性对象的绑定【从零开始学Spring Boot】
    (25)Spring Boot使用自定义的properties【从零开始学Spring Boot】
    《将博客搬至CSDN》
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9446158.html
Copyright © 2020-2023  润新知