学习笔记10-学习《精通UNIX下C语言编程及项目实践》
来源:互联网 发布:淘宝联盟手机能提现吗 编辑:程序博客网 时间:2024/06/05 20:51
十四章 共享内存
管道, 消息队列和信号量都需要借助第三方对象进行通信; 而共享内存正好弥补了这些缺陷, 它是最快的IPC对象. 在本质上, 共享内存是一端物理内存.
共享内存简介
共享内存中最重要的属性是内存大小和内存地址, 进程在访问共享内存前必须先将共享内存映射到进程空间的一个虚拟地址中, 然后任何对该虚拟地址的数据操作都将直接作用到物理内存上.
共享内存由进程创建, 但是进程结束时共享内存仍然保留, 除非该共享内存被显式地删除或者重启操作系统.
UNIX的内核采用结构shmid_ds来管理消息队列, 它的数据成员与命令'ipcs -a -m'的结果一一对应
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
命令'ipcs -m'查询系统中共享内存的基本信息:
[bill@billstone bill]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
[bill@billstone bill]$
使用共享内存
(1) 共享内存的创建
在UNIX中, 函数shmget用来创建或获取共享内存, 原型如下:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
同样的, 参数shm_flg有IPC_CREAT和IPC_EXCL两种取值.
(2) 共享内存的映射
与消息队列和信号量不同, 共享内存在获取标志号后, 仍需要调用shmat函数将共享内存映射到进程的地址空间后才能访问, 原型如下
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
(3) 共享内存的释放
当进程不再需要共享内存时, 可以使用函数shmdt释放共享内存内存映射, 原型如下
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
(4) 共享内存的控制
与消息队列和信号量一样, 共享内存也有自给的控制函数shmctl, 原型如下:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
这里设计一个类似于命令'ipcs'和命令'ipcrm'的程序ipcshm: 它从命令行参数中获取要执行的操作, 包括创建共享内存, 读取共享内存信息和删除共享内存等, 主体代码如下代码如下
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/stat.h>
#define VerifyErr(a, b) /
if (a) fprintf(stderr, "%s failed./n", (b)); /
else fprintf(stderr, "%s success./n", (b));
int main(int argc, char *argv[])
{
int shmid, size;
if(argc != 3)
exit(1);
shmid = atoi(argv[1]);
if(strcmp(argv[2], "v") == 0){
StatShm(shmid);
}
else if(strcmp(argv[2], "d") == 0){
VerifyErr(shmctl(shmid, IPC_RMID, NULL) < 0, "Delete Shm");
}
else{
size = atoi(argv[2]);
VerifyErr(shmget(shmid, size, 0666|IPC_CREAT|IPC_EXCL) < 0, "Create Shm");
}
return 0;
}
其中用到了两个函数:
char * GetFileMode(mode_t st_mode, char *resp){
if(resp == NULL)
return 0;
memset(resp, '-', 9);
if(st_mode & S_IRUSR) resp[0] = 'r';
if(st_mode & S_IWUSR) resp[1] = 'w';
if(st_mode & S_IXUSR) resp[2] = 'x';
if(st_mode & S_IRGRP) resp[3] = 'r';
if(st_mode & S_IWGRP) resp[4] = 'w';
if(st_mode & S_IXGRP) resp[5] = 'x';
if(st_mode & S_IROTH) resp[6] = 'r';
if(st_mode & S_IWOTH) resp[7] = 'w';
if(st_mode & S_IXOTH) resp[8] = 'x';
return resp;
}
int StatShm(int shmid){
char resp[10];
struct shmid_ds buf;
memset(&buf, 0, sizeof(buf));
memset(resp, 0, sizeof(resp));
shmctl(shmid, IPC_STAT, &buf);
fprintf(stderr, "T ID KEY MODE OWNER GROUP NATTCH SEGSZ CPID LPID/n");
fprintf(stderr, "m %6d %#6x %s %6d %6d %6d %10d %10d %10d/n", shmid, buf.shm_perm.__key,
GetFileMode(buf.shm_perm.mode, resp), buf.shm_perm.uid, buf.shm_perm.gid,
buf.shm_nattch, buf.shm_segsz, buf.shm_cpid, buf.shm_lpid);
return 0;
}
执行情况如下:
[bill@billstone Unix_study]$ gcc -o ipcshm ipcshm.c
[bill@billstone Unix_study]$ ./ipcshm 2000 100
Create Shm success.
[bill@billstone Unix_study]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x000007d0 229377 bill 666 100 0
[bill@billstone Unix_study]$ ./ipcshm 229377 v
T ID KEY MODE OWNER GROUP NATTCH SEGSZ CPID LPID
m 229377 0x7d0 rw-rw-rw- 500 500 0 100 1796 0
[bill@billstone Unix_study]$ ./ipcshm 229377 d
Delete Shm success.
[bill@billstone Unix_study]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
[bill@billstone Unix_study]$
(5) 共享内存实例
共享内存的应用可以分为打开(创建)共享内存, 映射共享内存, 读写共享内存和释放共享内存映射等四个步骤.
程序shm1想共享内存中指定位置写入数据.
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/stat.h>
#define VerifyErr(a, b) /
if (a) { fprintf(stderr, "%s failed./n", (b)); return; } /
else fprintf(stderr, "%s success./n", (b));
int main(void)
{
int shmid, no;
char *pmat = NULL, buf[1024];
VerifyErr((shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT)) == -1, "Open(Create) Shm");
VerifyErr((pmat = (char *)shmat(shmid, 0, 0)) == 0, "Link Shm");
printf("Please input NO.(0-9): ");
scanf("%d", &no);
VerifyErr(no<0 || no>9, "Input No.");
printf("Please input data: ");
memset(buf, 0, sizeof(buf));
getchar(); // 读入'/n'回车符
fgets(buf, sizeof(buf), stdin);
memcpy(pmat+no*1024, buf, 1024);
shmdt(pmat);
return 0;
}
程序shm2从共享内存指定位置读取数据
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/stat.h>
#define VerifyErr(a, b) /
if (a) { fprintf(stderr, "%s failed./n", (b)); return; } /
else fprintf(stderr, "%s success./n", (b));
int main(void)
{
int shmid, no;
char *pmat = NULL, buf[1024];
VerifyErr((shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT)) == -1, "Open(Create) Shm");
VerifyErr((pmat = (char *)shmat(shmid, 0, 0)) == 0, "Link Shm");
printf("Please input NO.(0-9): ");
scanf("%d", &no);
VerifyErr(no<0 || no>9, "Input No.");
memcpy(buf, pmat+no*1024, 1024);
printf("Data: [%s]/n", buf);
shmdt(pmat);
return 0;
}
运行结果如下
[bill@billstone Unix_study]$ make shm1
cc shm1.c -o shm1
[bill@billstone Unix_study]$ make shm2
cc shm2.c -o shm2
[bill@billstone Unix_study]$ ./shm1
Open(Create) Shm success.
Link Shm success.
Please input NO.(0-9): 1
Input No. success.
Please input data: this is a test!
[bill@billstone Unix_study]$ ./shm2
Open(Create) Shm success.
Link Shm success.
Please input NO.(0-9): 1
Input No. success.
Data: [this is a test!
]
[bill@billstone Unix_study]$
- 学习笔记10-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记01-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记02-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记03-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记04-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记05-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记06-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记07-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记08-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记09-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记11-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记12-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记13-学习《精通UNIX下C语言编程及项目实践》
- 学习《精通UNIX下C语言编程及项目实践》- 总结与展望(提供下载)
- Unix初学者的迷惑——《精通Unix下C语言编程与项目实践》读
- Unix与Windows是什么关系——《精通Unix下C语言编程与项目实践
- Unix朝代歌《精通Unix下C语言编程与项目实践》读书笔记(7)
- 《精通Unix下C语言编程与项目实践》读书笔记(1)
- 数据结构-图的建立与遍历
- Silverlight 3.0 RTW引入-- 鼠标滚动事件
- 学习笔记08-学习《精通UNIX下C语言编程及项目实践》
- 学习笔记09-学习《精通UNIX下C语言编程及项目实践》
- Silverlight明年将占据互联网设备半壁江山
- 学习笔记10-学习《精通UNIX下C语言编程及项目实践》
- 数据结构-稀疏矩阵(三元组表示)
- ubuntu 8.04建立mysql C开发环境
- 学习笔记11-学习《精通UNIX下C语言编程及项目实践》
- KMP算法实现
- 学习笔记12-学习《精通UNIX下C语言编程及项目实践》
- javascript 当前日期加(天、周、月、年)
- 数据库实用主义
- msdn技术资源库的一个小错误 Membership.GetAllUsers