进程通信之共享内存

来源:互联网 发布:share p图软件 编辑:程序博客网 时间:2024/05/23 19:18
1、共享内存

     –共享内存是进程间通信中最简单的方式之一。共享内存在各种进程间通信方式中具有最高的效率。因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。解决这些问题的常用方法是通过使用信号量进行同步。


2、int shmget(key_t key, size_t size, int shmflg)

      –shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT)

     –shmget得到一个共享内存标识符或创建一个共享内存对象

     –key:建立新的共享内存对象
     –size:新建立的内存大小(以字节为单位)
     –shmflg:标识符

例:

#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<stdio.h>#define BUFSZ 4096int main(void){int shm_id; /*共享内存标识符*/shm_id = shmget(IPC_PRIVTE, BUFSZ,0666);if(shm_id < 0) { /*创建共享内存*/perror("shmgget");exit(1);}printf("successfully created segment :%d\n",shm_id);system("ipcs -m"); /*调用ipcs命令查看IPC*/eixt(0);}

$gcc create_shm.c -o create_shm
$./create_shm
successfully created segment :98305
-------shared Memory segments--------
key                   shemid     owner          perms       bytes         nattch     status
0x00000000     0               linux-c         600           393216      2            dest
0x00000000     98305       linux-c         666           4096          0


3、将一个存在的共享内存连接到本进程空间

     void *shmat(int shmid, const void *shmaddr, int shmflg)

      –shmat(shmid, 0, 0)
      –返回共享的内存地址,否则返回-1
      –shmid:共享内存标识符
     –shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
     –shmflg SHM_RDONLY:为只读模式,其他为读写模式
addr 和 flag 组合 说明要引入的地址值,通常只有两种用法:

注:如函数成功返回值为实际引入的地址,如失败返回-1。shmat()函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加。

4、对共享内存段操作结束时从进程空间中脱离

      #include<sys/shm.h>
      int shmdt(void *addr);

      参数addr是调用shemat()函数的返回值,如函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,如失败返回-1。

例:

#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<stdio.h>int main(int argc, char *argv[]){int shm_id;char *shm_buf;if(argc != 2) {printf("USAGE: atshm <identifier>");exit(1);}shm_id = atoi(argv[1]);if((shm_buf = shmat(shm_id,0 ,0)) < (char *)0) {perror("shmat");exit(1);}printf("segment attached at %p\n", shm_buf);system("ipc -m");sleep(3);if((shmdt(shm_buf)) < 0) {perror("shmdt");exit(1);}printf("segment detached \n");system("ipcs -m");exit(0);}

$ gcc opr_shm.c -o opr_shm
segment attached at oxb7723000

key                  shemid         owner          perms              bytes               nattch        status
0x00000000    0                   linux-c         600                  393216            2               dest
0x00000000    98305           linux-c         666                  4096                1

key                  shemid          owner         perms              bytes               nattch        status
0x00000000    0                    linux-c         600                  393216            2                dest
0x00000000    98305            linux-c         666                  4096                0


5、int shmctl(int shmid, int cmd, struct shmid_ds *buf)
      –shmctl(shmid, IPC_RMID, 0) == -1
      –shmid:共享内存标识符
      –cmd IPC_RMID:删除这片共享内存
      –buf:共享内存管理结构体


cmd的值                           意义
        IPC_STAT                取shm_id 所指向内存共享段的shm_ds结构,对参数buf指向的结构赋值。
        IPC_SET                  使用buf指向的结构对,sh_mid段的相关结构赋值,只对以下几个域有作用。
                                          shm_perm.uid  shm_perm.gid  shm_perm.mode
                                          注意此命令只有具备以下条件的进程才可以请求:
                                          (1)进程的用户ID等于shm_perm.cuid shm_perm.uid
                                          (2)超级用户特权进程。
         IPC_RMID                删除shm_id所指向的共享内存段,只有当shmid_ds结构的shm_nattch 域为0时
                                          才会真正执行删除命令,否则不会删除该段。注意此命令的请求规则与IPC_SET命令相同
        SHM_LOCK              锁定共享内存段在内存,此命令只能由超级用户请求。
        SHM_UNLOCK         对共享内存段解锁,此命令只能由超级用户请求。


例:

shmdata.h

#ifndef _SHMDATA_H_HEADER  #define _SHMDATA_H_HEADER    #define TEXT_SZ 2048    struct shared_use_st  {      //作为一个标志,非0:表示可读,0表示可写int written;//记录写入和读取的文本    char text[TEXT_SZ];  };    #endif


shmread.h

#include <unistd.h>  #include <stdlib.h>  #include <stdio.h>  #include <sys/shm.h>  #include "shmdata.h"    int main(void)  {      int running = 1;//程序是否继续运行的标志      void *shm = NULL;//分配的共享内存的原始首地址      struct shared_use_st *shared;//指向shm      int shmid;//共享内存标识符      //创建共享内存      shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);      if(shmid == -1)      {          fprintf(stderr, "shmget failed\n");          exit(EXIT_FAILURE);      }      //将共享内存连接到当前进程的地址空间      shm = shmat(shmid, 0, 0);      if(shm == (void*)-1)      {          fprintf(stderr, "shmat failed\n");          exit(EXIT_FAILURE);      }      printf("\nMemory attached at %p\n", shm);      //设置共享内存      shared = (struct shared_use_st*)shm;      shared->written = 0;      while(running)//读取共享内存中的数据      {          //没有进程向共享内存定数据有数据可读取          if(shared->written != 0)          {              printf("You wrote: %s", shared->text);              sleep(rand() % 3);              //读取完数据,设置written使共享内存段可写              shared->written = 0;              //输入了end,退出循环(程序)              if(strncmp(shared->text, "end", 3) == 0)                  running = 0;          }          else//有其他进程在写数据,不能读取数据              sleep(1);      }      //把共享内存从当前进程中分离      if(shmdt(shm) == -1)      {          fprintf(stderr, "shmdt failed\n");          exit(EXIT_FAILURE);      }      //删除共享内存      if(shmctl(shmid, IPC_RMID, 0) == -1)      {          fprintf(stderr, "shmctl(IPC_RMID) failed\n");          exit(EXIT_FAILURE);      }      exit(EXIT_SUCCESS);  }

shmwrite.h

#include <unistd.h>  #include <stdlib.h>  #include <stdio.h>  #include <string.h>  #include <sys/shm.h>  #include "shmdata.h"    int main(void)  {      int running = 1;      void *shm = NULL;      struct shared_use_st *shared = NULL;      char buffer[BUFSIZ + 1];//用于保存输入的文本      int shmid;      //创建共享内存      shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);      if(shmid == -1)      {          fprintf(stderr, "shmget failed\n");          exit(EXIT_FAILURE);      }      //将共享内存连接到当前进程的地址空间      shm = shmat(shmid, (void*)0, 0);      if(shm == (void*)-1)      {          fprintf(stderr, "shmat failed\n");          exit(EXIT_FAILURE);      }      printf("Memory attached at %p\n", shm);      //设置共享内存      shared = (struct shared_use_st*)shm;      while(running)//向共享内存中写数据      {          //数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本          while(shared->written == 1)          {              sleep(1);              printf("Waiting...\n");          }          //向共享内存中写入数据          printf("Enter some text: ");          fgets(buffer, BUFSIZ, stdin);          strncpy(shared->text, buffer, TEXT_SZ);          //写完数据,设置written使共享内存段可读          shared->written = 1;          //输入了end,退出循环(程序)          if(strncmp(buffer, "end", 3) == 0)              running = 0;      }      //把共享内存从当前进程中分离      if(shmdt(shm) == -1)      {          fprintf(stderr, "shmdt failed\n");          exit(EXIT_FAILURE);      }      sleep(2);      exit(EXIT_SUCCESS);  }




0 0
原创粉丝点击