共享内存函数: 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 }

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;
另外, 再附一个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

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 }

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
本次例子中, shm1.c 作用是作为消费者创建共享内存并把该内存中的内容显示出来, shm2.c 作用是作为生产者往共享内存中写数据.
shm1.c: 创建共享内存段, 然后把他连接到自己的地址空间. 我们在共享内存的开始处使用了一个结构shared_use_st.该结构中有一个标志written_by_you. 当共享内存中有数据写入, 就设置该标志, 程序就从共享内存中读取文本, 并将它们打印出来, 然后清楚这个标志表示已经读完数据,shm2.c: 使用了相同的键1234来取得并连接同一个共享内存段, 然后他提示用户输入一些文本. 如果标志written_by_you被设置, shm2就知道客户进程还没有读取完上一次的数据, 因此就继续等待. 当其他的进程清楚这个标志后, shm2写入新数据并设置该标志