zoukankan      html  css  js  c++  java
  • 进程间通信--共享内存

    共享内存函数: shmget, shmat, shmctl, shmdt

    #include<sys/sem.h>
    int shmget(key_t key, size_t size, int shmflg)
    void shmat(int shm_id, const void *shm_addr, int shmflg)
    int shmdt(const void *shm_addr)
    int shmctl(int shm_id, int command, struct shmid_ds *buf)
     
    int
    头文件 sys/sem.h 通常依赖于 sys/types.h 和 sys/ipc.h. 一般情况下, 他们都会被 sys/sem.h 自动包含.
     
    1. shmget函数
    int shmget(key_t sem_id, size_t size, int shmflg)
    key: 与信号量一样, 程序需要提供一个参数key, 他有效地为共享内存段命名. shmget函数返回一个共享内存标识, 该标识用于后续的共享内存函数. 有一个特殊的键IPC_PRIVATE, 他用于创建一个只属于创建进程的共享内存.通常,你不会用到这个值, 而且你可能发现在一些Linux系统中, 私有的共享内存其实并不是真真的私有.
    size: 以字节为单位指定需要的共享内存的大小
    shmflg: 包含9个比特的权限标志, 他们的作用与创建文件时使用的mode标志一致. 由于IPC_CREAT定义的一个特殊比特,必须和权限标志按位或才能够创建一个新的共享内存段. 设置IPC_CREATE标志的同时, 给shmget函数传递一个已有共享内存段的键并不是一个错误, 如果无需用到IPC_CREATE标志,那么该标志就会被悄悄的忽略掉.
     
    2. shmat函数
    void shmat(int shm_id, const void *shm_addr, int shmflg)
    第一次创建共享内存段, 他不能够被任何进程访问, 要想启用对该共享内存的访问, 必须将其连接到一个进程的地址空间中. 这项工作由shmat函数来完成.
    shm_id: 由shmget返回的共享内存标识符.
    shm_addr: 指定共享内存连接到当前进程中的地理位置. 他通常是一个空指针, 表示让系统来选择共享内存出现的地址.
    shmflg: 是一组位标志. 他的两个可能值是SHM_RND(这个标志和shm_addr联合使用, 用来控制共享内存连接的地址)和SHM_RDONLY(他是的连接的内存只读). 我们很少需要控制内存的连接地址, 通常都是让系统自己来选择一个地址, 否则就会使应用程序对硬件的依赖性过高.如果shmat调用成功, 他返回一个指向共享内存第一个字节的指针; 如果失败, 那么他就返回-1;
    共享内存的读写权限由他的属主(共享内存的创建者), 他的访问权限和当前进程的属主决定. 共享内存的访问权限类似于文件的访问权限.
    这个规则的一个例外: 当shmflg&SHM_RDONLY为true的时候, 此时即使该共享内存的访问权限允许写操作, 他都不能够被写入
     
    3. shmdt函数
    int shmdt(const void *shm_addr)
    shmdt函数的作用是将共享内存从当前进程中被分离. 他的参数是shmat返回的地址指针. 成功时返回0; 失败返回-1. 尤其注意的是: 该函数是将共享内存分离但是并没有真真的删除他, 只是使得该共享内存对该进程不可用.
     
    4. shmctl函数
    int shmctl(int shm_id, int command, struct shmid_ds *buf)
    与复杂的信号量控制函数相比, 共享内存的控制函数要简单一些. 
    shmid_ds结构体至少含有以下成员:
    struct shmid_ds
    {
         uid_t shm_perm.uid;
         uid_t shm_perm.gid;
         mode_t shm_perm.mode;
    }
    shm_id: 是shmget返回的共享内存标识符
    command: 是要采取的动作, 他可以取3个值
    1) IPC_STAT: 把shmid_ds结构中的数据设置为共享内存的当前关联值
    2) IOC_SET: 如果进程有足够权限, 就把共享内存的当前关联值设置为shmid_ds结构给出的值
    3) IPC_RMID删除共享内存段
    buf: 他是一个指针, 他指向包含共享内存模式和访问权限的结构.
    成功: 返回0, 失败: 返回-1
     
    5. pid_t fork(void)
    fork() creates a new process by duplicating the calling process
     
    6. int execl(const char *path, const char *arg, ...)
    The  exec()  family of functions replaces the current process image with a new process image.
    path: 路径(包含程序名字)
    arg: 程序名
    ...: other args
    需要注意的是, ...的最后一个参数是 (char*)0 结尾
     
    7. fork与exec类函数配合使用
    1. 用fork创建子进程
    2. 在子进程之调用exec启动新的应用程序
     
     1 /*******************************************************************************
     2 * 版权所有:
     3 * 模 块 名:
     4 * 文 件 名:shm.c
     5 * 实现功能:
     6 * 作    者:XYZ
     7 * 版    本:V1.0
     8 * 日    期:2013.07.22
     9 * 联系方式:xiao13149920@foxmail.com
    10 * 其他说明:
    11 ********************************************************************************/
    12 // shm.c
    13 #include<stdio.h>
    14 #include <sys/ipc.h>
    15 #include<sys/shm.h>
    16 #include<sys/stat.h>
    17 #include<unistd.h>
    18 #include<stdlib.h>
    19 
    20 int main()
    21 {
    22     int segment_id;
    23     char* shared_memory;
    24     struct shmid_ds shmbuffer;
    25     int segment_size;
    26     const int shared_segment_size = 0x6400;
    27 
    28     // 1. shmget: allocate a block share memory
    29     //segment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
    30     //segment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_EXCL|S_IRUSR|S_IWUSR);
    31     segment_id = shmget((key_t)1234, shared_segment_size, IPC_CREAT|0666);
    32     if (segment_id == -1)
    33     {
    34         fprintf(stderr, "shmget failed
    ");
    35 
    36         exit(EXIT_FAILURE);
    37     }
    38     // 2. shmat: 绑定
    39     shared_memory = (char*)shmat(segment_id, 0, 0);
    40     //shared_memory = (char*)shmat(segment_id, (void*)0x500000, 0);
    41     if (shared_memory == (void*)-1)
    42     {
    43         fprintf(stderr, "shmat failed
    ");
    44         exit(EXIT_FAILURE);
    45     }
    46     printf("share memory attached at address %p
    ", shared_memory);
    47     
    48     // 3. shmctl: share memory size
    49     shmctl(segment_id, IPC_STAT, &shmbuffer);
    50     segment_size = shmbuffer.shm_segsz;
    51     printf("segment size:%d
    ", segment_size);
    52 
    53     // do sth in shared memory...
    54     // 往共享内存中写入字符串
    55     sprintf(shared_memory, "hello world
    ");
    56     
    57     // 脱离了共享内存块
    58     if (shmdt(shared_memory)==-1)
    59     {
    60         fprintf(stderr, "shmdt failed
    ");
    61         exit(EXIT_FAILURE);
    62     }
    63 
    64 #if 0
    65     // 重新绑定该内存
    66     shared_memory = (char*)shmat(segment_id, (void*)0x500000, 0);
    67     printf("shared memory reattached at address %p
    ", shared_memory);
    68     // 输出共享内存中的字符串
    69     printf("%s
    ", shared_memory);
    70     // 脱离该共享内存
    71     shmdt (shared_memory);
    72 
    73     // 释放共享内存
    74     shmctl(segment_id, IPC_RMID, 0);
    75 #else
    76     if (fork()!=0)
    77     {
    78         printf("file:%s, line:%d
    ", __FILE__, __LINE__);
    79         //sleep(10);
    80     }
    81     else
    82     {    
    83         char path[256];
    84         sprintf(path, "/opt/work/xyz/alp/sub_shm");
    85         if (execl(path, "sub_shm", (char*)0) < 0)
    86         {
    87             perror("execlp error
    ");
    88         }
    89     }
    90 #endif
    91     printf("this is test for shmget shmat shmdt
    ");
    92 
    93     return 0;
    94 }
    View Code
     1 // sub_shm.c
     2 #include<stdio.h>
     3 #include <sys/ipc.h>
     4 #include<sys/shm.h>
     5 #include<sys/stat.h>
     6 #include<unistd.h>
     7 #include<stdlib.h>
     8 
     9 int main()
    10 {
    11     int segment_id;
    12     char* shared_memory;
    13     const int shared_segment_size = 0x6400;
    14     char buffer[shared_segment_size+1];
    15 
    16     //sleep(25);
    17     segment_id = shmget((key_t)1234, shared_segment_size, IPC_CREAT|0666);
    18     if (segment_id == -1)
    19     {
    20         fprintf(stderr, "shmget failed
    ");
    21         exit(EXIT_FAILURE);
    22     }
    23 
    24     //shared_memory = (char*)shmat(segment_id, (void*)0x500000, SHM_RDONLY);
    25     shared_memory = (char*)shmat(segment_id, NULL,0);
    26     if (shared_memory == (void *)-1)
    27     {
    28         fprintf(stderr, "shmat failed
    ");
    29         exit(EXIT_FAILURE);
    30     }
    31     printf("shared memory reattached at address %p
    ", shared_memory);
    32     
    33     //shmctl(segment_id, IPC_STAT, &buffer);
    34     char* buf = (char*)shared_memory;
    35     // 输出共享内存中的字符串
    36     printf("%s
    ", buf);
    37     // 脱离该共享内存
    38     if (shmdt (shared_memory) == -1)
    39     {
    40         fprintf(stderr, "shmdt failed
    ");
    41         exit(EXIT_FAILURE);
    42     }
    43     // 释放共享内存
    44     shmctl(segment_id, IPC_RMID, 0);
    45 
    46     return 0;
    View Code

    另外, 再附一个shmget的进程间通信例子

    // shm_com.h
    #ifndef __SHM_COM_H__
    #define __SHM_COM_H__
    
    #define TEXT_SZ 2048
    struct shared_use_st
    {
                     int written_by_you;
                     char some_text[TEXT_SZ];
    };
    
    #endif
    View Code
     1 //shm1.c
     2 #include<stdio.h>
     3 #include<unistd.h>
     4 #include<stdlib.h>
     5 #include<string.h>
     6 
     7 #include<sys/shm.h>
     8 
     9 #include"shm_com.h"
    10 
    11 #define BUFSIZE 2048
    12 
    13 int main()
    14 {
    15                  int running = 1;
    16                  void *shared_memory = (void *)0;
    17                  struct shared_use_st *shared_stuff;
    18                  char buffer[BUFSIZE];
    19                  int shmid;
    20 
    21                 shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
    22 
    23                  if (shmid == -1)
    24                 {
    25                                 fprintf(stderr, "shmget failed
    ");
    26                                 exit(EXIT_FAILURE);
    27                 }
    28 
    29                 shared_memory = shmat(shmid, NULL, 0);
    30                  if (shared_memory == (void *)-1)
    31                 {
    32                                 fprintf(stderr, "shmat failed");
    33                                 exit(EXIT_FAILURE);
    34                 }
    35 
    36                 printf( "Memory attached at %X
    " , (int)shared_memory);
    37                 shared_stuff = ( struct shared_use_st *)shared_memory;
    38                 shared_stuff->written_by_you = 0;
    39                  while (running)
    40                 {
    41                                  if (shared_stuff->written_by_you)
    42                                 {
    43                                                 printf( "You wrote: %s", shared_stuff->some_text);
    44                                                 sleep(rand()%4); //make the other process wait for us
    45                                                 shared_stuff->written_by_you = 0;
    46                                                  if (strncmp(shared_stuff->some_text,"end", 3)==0)
    47                                                 {
    48                                                                 running = 0;
    49                                                 }
    50                                 }
    51                 }
    52 
    53                  if (shmdt(shared_memory) == -1)
    54                 {
    55                                 fprintf(stderr, "shmdt failed
    ");
    56                                 exit(EXIT_FAILURE);
    57                 }
    58 
    59                  if (shmctl(shmid, IPC_RMID, 0) == -1)
    60                 {
    61                                 fprintf(stderr, "shmctl failed
    ");
    62                                 exit(EXIT_FAILURE);
    63                 }
    64 
    65                  return 0;
    66 }
    View Code
     1 // shm2.c
     2 #include<stdio.h>
     3 #include<unistd.h>
     4 #include<stdlib.h>
     5 #include<string.h>
     6 
     7 #include<sys/shm.h>
     8 
     9 #include"shm_com.h"
    10 
    11 #define BUFSIZE 2048
    12 
    13 int main()
    14 {
    15                  int running = 1;
    16                  void *shared_memory = (void *)0;
    17                  struct shared_use_st *shared_stuff;
    18                  char buffer[BUFSIZE];
    19                  int shmid;
    20 
    21                 shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
    22 
    23                  if (shmid == -1)
    24                 {
    25                                 fprintf(stderr, "shmget failed
    ");
    26                                 exit(EXIT_FAILURE);
    27                 }
    28 
    29                 shared_memory = shmat(shmid, NULL, 0);
    30                  if (shared_memory == (void *)-1)
    31                 {
    32                                 fprintf(stderr, "shmat failed");
    33                                 exit(EXIT_FAILURE);
    34                 }
    35 
    36                 printf( "Memory attached at %X
    " , (int)shared_memory);
    37                 shared_stuff = ( struct shared_use_st *)shared_memory;
    38                  while (running)
    39                 {
    40                                  while (shared_stuff->written_by_you == 1)
    41                                 {
    42                                                 sleep(1);
    43                                                 printf( "waiting for client...
    " );
    44                                 }
    45 
    46                                 printf( "Enter some text: ");
    47                                 fgets(buffer, BUFSIZE, stdin);
    48 
    49                                 strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
    50                                 shared_stuff->written_by_you = 1;
    51 
    52                                  if (strncmp(buffer, "end" , 3) == 0)
    53                                 {
    54                                                 running = 0;
    55                                 }
    56                 }
    57 
    58 
    59                  if (shmdt(shared_memory) == -1)
    60                 {
    61                                 fprintf(stderr, "shmdt failed
    ");
    62                                 exit(EXIT_FAILURE);
    63                 }
    64 
    65                  return 0;
    66 } 
    67   
    View Code
    本次例子中, shm1.c 作用是作为消费者创建共享内存并把该内存中的内容显示出来, shm2.c 作用是作为生产者往共享内存中写数据.
    shm1.c: 创建共享内存段, 然后把他连接到自己的地址空间. 我们在共享内存的开始处使用了一个结构shared_use_st.该结构中有一个标志written_by_you. 当共享内存中有数据写入, 就设置该标志, 程序就从共享内存中读取文本, 并将它们打印出来, 然后清楚这个标志表示已经读完数据,shm2.c: 使用了相同的键1234来取得并连接同一个共享内存段, 然后他提示用户输入一些文本. 如果标志written_by_you被设置, shm2就知道客户进程还没有读取完上一次的数据, 因此就继续等待. 当其他的进程清楚这个标志后, shm2写入新数据并设置该标志
  • 相关阅读:
    mysql主从与mycat与MHA
    mycat+mysql集群:实现读写分离,分库分表
    centos7下扩展根分区(图文详解)
    MySQL高可用之MHA的搭建
    zabbix_agentd客户端安装与配置(windows操作系统)
    centos7手把手教你搭建zabbix监控
    有关添加System.Web的问题
    锚标签<a>
    MVC3出现“提供程序未返回 ProviderManifestToken 字符串”的解决办法
    解决.net后台调用js弹窗后,前台界面样式乱掉问题
  • 原文地址:https://www.cnblogs.com/xiao13149920yanyan/p/3210353.html
Copyright © 2011-2022 走看看