标签:进程间通信
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