谁注册了丁丁

导航

进程间通信--共享内存

共享内存函数: 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
详见: http://www.cnblogs.com/xiao13149920yanyan/p/3210872.html 
 
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\n");
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\n");
44         exit(EXIT_FAILURE);
45     }
46     printf("share memory attached at address %p\n", 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\n", segment_size);
52 
53     // do sth in shared memory...
54     // 往共享内存中写入字符串
55     sprintf(shared_memory, "hello world\n");
56     
57     // 脱离了共享内存块
58     if (shmdt(shared_memory)==-1)
59     {
60         fprintf(stderr, "shmdt failed\n");
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\n", shared_memory);
68     // 输出共享内存中的字符串
69     printf("%s\n", 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\n", __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\n");
88         }
89     }
90 #endif
91     printf("this is test for shmget shmat shmdt\n");
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\n");
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\n");
29         exit(EXIT_FAILURE);
30     }
31     printf("shared memory reattached at address %p\n", shared_memory);
32     
33     //shmctl(segment_id, IPC_STAT, &buffer);
34     char* buf = (char*)shared_memory;
35     // 输出共享内存中的字符串
36     printf("%s\n", buf);
37     // 脱离该共享内存
38     if (shmdt (shared_memory) == -1)
39     {
40         fprintf(stderr, "shmdt failed\n");
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\n");
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\n" , (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\n");
56                                 exit(EXIT_FAILURE);
57                 }
58 
59                  if (shmctl(shmid, IPC_RMID, 0) == -1)
60                 {
61                                 fprintf(stderr, "shmctl failed\n");
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\n");
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\n" , (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...\n" );
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\n");
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写入新数据并设置该标志

posted on 2013-07-24 12:05  leaker  阅读(420)  评论(0编辑  收藏  举报