Chinaunix首页 | 论坛 | 博客
  • 博客访问: 376452
  • 博文数量: 105
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 826
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-16 13:58
个人简介

记录有意义的东西

文章分类

全部博文(105)

文章存档

2013年(105)

我的朋友

分类: LINUX

2013-04-22 15:11:47

共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换信息,内核专门留出一块内存区, 这段内存区可以由需要访问的进程将其映射到自己的私有地址空间,因此进程可以直接读写这一内存区而不需要数据的复制,从而大大提高效率。
当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。

共享内存的实现有两个步骤:
一、调用shmget创建共享内存,就是在内存中获得一端共享内存区域。
二、调用shmat映射共享内存,就是把这段创建的共享内存映射到具体的进程空间中,到这,可以用不带io缓冲的函数对其操作了。使用shmdt取消映射。
三、删除共享内存,用shmctl函数。

四个函数原型是:
#include
#include

int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

一般用法是:
key_t key;
int shmid;
char *shmaddr;
char buf[64];

key = ftok(".", 'a');
shmid = shmget(key, sizeof(buf), 0666);
//shmid = shmget(IPC_PRIVATE, sizeof(buf), 0666 | IPC_CREAT);
shmaddr = shmat(shmid, NULL, 0);
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL);

下面看一个例子,首先是创建一个共享内存,以下称shm(用的键值是IPC_CREAT,因为创建的shm是父子进程之间的功用部分),之后创建子进程,在父子两个进程中将shm分别映射到各自的进程地址空间中。
父 进程先等待用户输入,然后将输入的字符串写入到shm,(strncpy(shmaddr+strlen(flag), buf, strlen(buf)))此时要为flag预留出地方,之后将flag指向的字符串写入shm的头部(strncpy(shmaddr, flag, strlen(flag))),表示父进程已成功写入数据,子进程一直等到shm的头部是wrote,然后将shm中的有效数据打印,两个进程都解除和 shm的映射关系。用标志字符串实现同步。

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9
 10 char buf[64];
 11
 12 int main(int argc, char *argv[])
 13 {
 14     pid_t pid;
 15     int shmid;
 16     char *shmaddr;
 17     char *flag = "wrote";
 18
 19     if((shmid = shmget(IPC_PRIVATE, sizeof(buf), 0666 | IPC_CREAT)) < 0 )
 20     {  perror("shmget error");
 21        exit(-1);
 22     }
 23     else
 24     {  printf("create shared memmory, id is %d\n", shmid); }
 25
 26     system("ipcs -m");
 27
 28     pid = fork();
 29     if(pid < 0)
 30     {  perror("fork error");
 31        exit(-1);
 32     }
 33
 34     if(pid == 0)
 35     {  if((shmaddr = shmat(shmid, NULL, 0)) < 0)
 36        {   perror("shmat error");
 37            exit(-1);
 38        }
 39        else
 40        {  printf("child shm attach address is %p\n", shmaddr); }
 41
 42        system("ipcs -m");
 43
 44        while(strncmp(shmaddr, flag, strlen(flag)) != 0)
 45        {
 46           printf("child :waiting for valid data........\n");
 47           sleep(8);
 48        }
 49
 50        strcpy(buf, shmaddr + strlen(flag));
 51        printf("child copy from shm, is %s\n", buf);
 52
 53        if(shmdt(shmaddr) < 0)
 54        {   perror("shmdt error");
 55            exit(-1);
 56        }
 57        else
 58        {   printf("child shm dettach\n");  }
 59
 60        if(shmctl(shmid, IPC_RMID, NULL) < 0)
 61        {   perror("shmctl error");
 62            exit(-1);
 63        }
 64        else
 65        {   printf("child shm remove\n"); }
 66     }
 67
 68     if(pid > 0)
 69     {
 70         if((shmaddr = shmat(shmid, NULL, 0)) < 0)
 71         {  perror("shmat error");
 72            exit(-1);
 73         }
 74         else
 75         {  printf("parent shm attach address is %p\n", shmaddr); }
 76
 77         sleep(1);
 78         printf("input some into shm: \n");
 79         fgets(buf, sizeof(buf), stdin);
 80         strncpy(shmaddr+strlen(flag), buf, strlen(buf));
 81         strncpy(shmaddr, flag, strlen(flag));
 82
 83         if(shmdt(shmaddr) < 0)
 84         {  perror("shmdt error");
 85            exit(-1);
 86         }
 87         else
 88         {  printf("parent shm dettach\n"); }
 89
 90         system("ipcs -m");
 91
 92         waitpid(pid, NULL, 0);
 93         system("ipcs -m");
 94         printf("finished\n");
 95     }
 96     exit(0);
 97 }


阅读(744) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~