标签:进程间通信
1. 基本特点
1)两个或者更多进程,共享同一块由系统内核负责维护的内存区域,其地址空间通常被映射到堆和栈之间。
如图所示,每个进程都有自己的share memory,共享内存其实是内核中的一块空间,是对不同进程share memory的映射,对share memory的操作实质就是对内核中共享内存的操作,操作形式和普通内存没什么区别。
2) 无需复制信息,最快的一种IPC机制,所以适合大文件的传输。struct shmid_ds {
struct ipc_perm shm_perm; // 所有者及其权限
size_t shm_segsz; // 大小(以字节为单位)
time_t shm_atime; // 最后加载时间
time_t shm_dtime; // 最后卸载时间
time_t shm_ctime; // 最后改变时间
pid_t shm_cpid; // 创建进程PID
pid_t shm_lpid; // 最后加载/卸载进程PID
shmatt_t shm_nattch; // 当前加载计数
...
};
struct ipc_perm {
key_t __key; // 键值
uid_t uid; // 有效属主ID
gid_t gid; // 有效属组ID
uid_t cuid; // 有效创建者ID
gid_t cgid; // 有效创建组ID
unsigned short mode; // 权限字
unsigned short __seq; // 序列号
};
2. 常用函数:
1) 创建/获取共享内存
int shmget (key_t key, size_t size, int shmflg);A. 该函数以key参数为键值创建共享内存, 或获取已有的共享内存。
D. 成功返回共享内存标识,失败返回-1。
2) 加载共享内存 , 即建立一个映射void* shmat (int shmid, const void* shmaddr,int shmflg);A. 将shmid参数所标识的共享内存,映射到调用进程的地址空间。
int shmdt (const void* shmaddr);A. 从调用进程的地址空间中,取消由shmaddr参数所指向的,共享内存映射区域。
4) 销毁/控制共享内存
int shmctl (int shmid, int cmd, struct shmid_ds* buf);A. cmd取值:
wshm.c
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
int main (void) {
printf ("创建共享内存...\n");
key_t key = ftok (".", 100);
if (key == -1) {
perror ("ftok");
return -1;
}
int shmid = shmget (key, 4096, 0644 | IPC_CREAT | IPC_EXCL);
if (shmid == -1) {
perror ("shmget");
return -1;
}
printf ("加载共享内存...\n");
void* shmaddr = shmat (shmid, NULL, 0);
if (shmaddr == (void*)-1) {
perror ("shmat");
return -1;
}
printf ("写入共享内存...\n");
sprintf (shmaddr, "我是%u进程写入的数据。", getpid ());
printf ("按<回车>卸载共享内存(0x%08x/%d)...", key, shmid);
getchar ();
if (shmdt (shmaddr) == -1) {
perror ("shmdt");
return -1;
}
printf ("按<回车>销毁共享内存(0x%08x/%d)...", key, shmid);
getchar ();
if (shmctl (shmid, IPC_RMID, NULL) == -1) {
perror ("shmctl");
return -1;
}
printf ("大功告成!\n");
return 0;
}
使用ipcs -m 命令我们可以得到系统中刚创建的共享内存:
rshm.c
#include <stdio.h>
#include <sys/shm.h>
int shmstat (int shmid) {
struct shmid_ds shm;
if (shmctl (shmid, IPC_STAT, &shm) == -1) {
perror ("shmctl");
return -1;
}
printf ("------------------------------------------------\n");
printf (" 共享内存信息\n");
printf ("----+----------------+--------------------------\n");
printf (" 所 | 键值 | 0x%08x\n", shm.shm_perm.__key);
printf (" 有 | 有效属主ID | %u\n", shm.shm_perm.uid);
printf (" 者 | 有效属组ID | %u\n", shm.shm_perm.gid);
printf (" 及 | 有效创建者ID | %u\n", shm.shm_perm.cuid);
printf (" 其 | 有效创建组ID | %u\n", shm.shm_perm.cgid);
printf (" 权 | 权限字 | %#o\n", shm.shm_perm.mode);
printf (" 限 | 序列号 | %u\n", shm.shm_perm.__seq);
printf ("----+----------------+--------------------------\n");
printf (" 大小(字节) | %u\n", shm.shm_segsz);
printf (" 最后加载时间 | %s", ctime (&shm.shm_atime));
printf (" 最后卸载时间 | %s", ctime (&shm.shm_dtime));
printf (" 最后改变时间 | %s", ctime (&shm.shm_ctime));
printf (" 创建进程ID | %u\n", shm.shm_cpid);
printf (" 最后加载/卸载进程ID | %u\n", shm.shm_lpid);
printf (" 当前加载计数 | %u\n", shm.shm_nattch);
printf ("---------------------+--------------------------\n");
return 0;
}
int shmset (int shmid) {
struct shmid_ds shm;
if (shmctl (shmid, IPC_STAT, &shm) == -1) {
perror ("shmctl");
return -1;
}
shm.shm_perm.mode = 0600;
shm.shm_segsz = 8192;
if (shmctl (shmid, IPC_SET, &shm) == -1) {
perror ("shmctl");
return -1;
}
return 0;
}
int main (void) {
printf ("获取共享内存...\n");
key_t key = ftok (".", 100);
if (key == -1) {
perror ("ftok");
return -1;
}
int shmid = shmget (key, 0, 0);
if (shmid == -1) {
perror ("shmget");
return -1;
}
printf ("加载共享内存...\n");
void* shmaddr = shmat (shmid, NULL, 0);
if (shmaddr == (void*)-1) {
perror ("shmat");
return -1;
}
shmstat (shmid);
printf ("读取共享内存...\n");
printf ("共享内存(0x%08x/%d):%s\n", key, shmid, shmaddr);
printf ("卸载共享内存...\n");
if (shmdt (shmaddr) == -1) {
perror ("shmdt");
return -1;
}
shmstat (shmid);
printf ("设置共享内存...\n");
shmset (shmid);
shmstat (shmid);
printf ("大功告成!\n");
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:进程间通信
原文地址:http://blog.csdn.net/meetings/article/details/47124775