分类: 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 }