1. 共享内存 - 概念
共享内存,主要是实现进程间大量数据的传输。所谓共享内存,即在内存中开辟一段特殊的内存空间,多个进程可互斥访问,该内存空间具有自身特有的数据结构。
共享内存的数据结构如下 - struct shmid_ds:
/* Come from /usr/include/linux/shm.h */
/* Obsolete, used only for backwards compatibility and libc5 compiles */
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 */
};
多个进程在使用此共享内存空间时候,必须在进程地址空间与共享内存地址空间之间建立连接,即将共享内存空间挂载到进程中;
共享内存是由一个进程开辟,其它任何进程都可以挂载;
共享内存并不会随着进程的退出而消失,因此最后不使用此内存空间时,必须要手动删除。
2. 共享内存管理
1). 创建共享内存 - shmget
- 作用:
创建一个共享内存空间头文件:
#include <sys/shm.h>
函数原型:
int shmget(key_t key, size_t size, int shmflg)
参数:
- key:
ftok()
的返回值- size: 想要创建的共享内存的大小 (字节)
- shmflg: 共享内存段的创建标识
Macro No. Description Head File IPC_CREAT 01000 若key内存段不存在,则创建;否则返回内存首地址 /usr/include/linux/ipc.h IPC_EXCL 02000 若key内存段存在,则返回错误 IPC_NOWAIT 04000 不等待直接返回 shm_r 0400 可读 /usr/include/linux/shm.h shm_w 0200 可写 /usr/include/linux/shm.h 返回值:
成功:共享内存空间的标志 shm_id
失败:-1
2). 共享内存控制 - shmctl
- 作用:
对共享内存进程操作,包括:读取/设置状态,删除操作头文件:
#include<sys/shm.h>
函数原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数:
- shmid :
shmget()
返回值- buf:临时共享内存变量信息
- cmd :
Macro No. Description Return IPC_RMID 0 删除 0 IPC_SET 1 设置 ipc_perm 参数 0 IPC_STAT 2 获取 ipc_perm 参数 IPC_INFO 3 若 ipcs
命令SHM_LOCK 11 锁定共享内存段 0 SHM_UNLOCK 12 解锁共享内存段 0 返回值:
成功:
失败:-1
3). 共享内存映射 - shmat()
- 作用:
将共享内存空间挂载到进程中头文件:
扫描二维码关注公众号,回复: 2263710 查看本文章#include <sys/shm.h>
函数原型:
void *shmat(int shmid, const void *shmaddr, int shmflg)
参数:
- shmid :
shmget()
返回值- shmaddr: 共享内存的映射地址,一般为0(由系统自动分配地址)
- shmflg : 访问权限和映射条件
Macro No. Descripton Remind - 0 默认有读写权限 常用 SHM_RDONLY 010000 只读 SHM_RDN 020000 Round attach address to SHMLBA boundary SHM_REMAP 040000 take-over region on attach 返回值:
成功:共享内存段首地址
失败:NULL / (void *)-1
4). 共享内存分离 - shmdt()
- 作用:
将进程与共享内存空间分离 (只是与共享内存不再有联系,并没有删除共享内存)头文件:
#include <sys/shm.h>
函数原型:
int shmdt(const void *shmaddr)
参数:
shmaddr:共享内存的首地址
返回值:
成功: 0
失败: -1
3. 示例代码:
两个进程通过共享内存传输数据,因共享内存不可同时读写,因此采用二元信号量进行进程互斥,具体操作如下:
- init: 设置信号量为0,此时只允许写入,不允许读取(因为共享内存没有数据);
- Sender: 在sem=0时,写入数据到共享内存(阻塞读);写入完成后,sem=1,此时可以读取,不可以写入;
- Receiver: 在sem=1时,读取数据;读取完成后,sem=0,此时只允许写入。
/* * Filename: Sender.c * Description: */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sem.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <string.h> int main(int argc, char *argv[]) { key_t key; int shm_id; int sem_id; int value = 0; //1.Product the key key = ftok(".", 0xFF); //2. Creat semaphore for visit the shared memory sem_id = semget(key, 1, IPC_CREAT|0644); if(-1 == sem_id) { perror("semget"); exit(EXIT_FAILURE); } //3. init the semaphore, sem=0 if(-1 == (semctl(sem_id, 0, SETVAL, value))) { perror("semctl"); exit(EXIT_FAILURE); } //4. Creat the shared memory(1K bytes) shm_id = shmget(key, 1024, IPC_CREAT|0644); if(-1 == shm_id) { perror("shmget"); exit(EXIT_FAILURE); } //5. attach the shm_id to this process char *shm_ptr; shm_ptr = shmat(shm_id, NULL, 0); if(NULL == shm_ptr) { perror("shmat"); exit(EXIT_FAILURE); } //6. Operation procedure struct sembuf sem_b; sem_b.sem_num = 0; //first sem(index=0) sem_b.sem_flg = SEM_UNDO; sem_b.sem_op = 1; //Increase 1,make sem=1 while(1) { if(0 == (value = semctl(sem_id, 0, GETVAL))) { printf("\nNow, snd message process running:\n"); printf("\tInput the snd message: "); scanf("%s", shm_ptr); if(-1 == semop(sem_id, &sem_b, 1)) { perror("semop"); exit(EXIT_FAILURE); } } //if enter "end", then end the process if(0 == (strcmp(shm_ptr ,"end"))) { printf("\nExit sender process now!\n"); break; } } shmdt(shm_ptr); return 0; }
/* * Filename: Receiver.c * Description: */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sem.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <string.h> int main(int argc, char *argv[]) { key_t key; int shm_id; int sem_id; int value = 0; //1.Product the key key = ftok(".", 0xFF); //2. Creat semaphore for visit the shared memory sem_id = semget(key, 1, IPC_CREAT|0644); if(-1 == sem_id) { perror("semget"); exit(EXIT_FAILURE); } //3. init the semaphore, sem=0 if(-1 == (semctl(sem_id, 0, SETVAL, value))) { perror("semctl"); exit(EXIT_FAILURE); } //4. Creat the shared memory(1K bytes) shm_id = shmget(key, 1024, IPC_CREAT|0644); if(-1 == shm_id) { perror("shmget"); exit(EXIT_FAILURE); } //5. attach the shm_id to this process char *shm_ptr; shm_ptr = shmat(shm_id, NULL, 0); if(NULL == shm_ptr) { perror("shmat"); exit(EXIT_FAILURE); } //6. Operation procedure struct sembuf sem_b; sem_b.sem_num = 0; //first sem(index=0) sem_b.sem_flg = SEM_UNDO; sem_b.sem_op = -1; //Increase 1,make sem=1 while(1) { if(1 == (value = semctl(sem_id, 0, GETVAL))) { printf("\nNow, receive message process running:\n"); printf("\tThe message is : %s\n", shm_ptr); if(-1 == semop(sem_id, &sem_b, 1)) { perror("semop"); exit(EXIT_FAILURE); } } //if enter "end", then end the process if(0 == (strcmp(shm_ptr ,"end"))) { printf("\nExit the receiver process now!\n"); break; } } shmdt(shm_ptr); //7. delete the shared memory if(-1 == shmctl(shm_id, IPC_RMID, NULL)) { perror("shmctl"); exit(EXIT_FAILURE); } //8. delete the semaphore if(-1 == semctl(sem_id, 0, IPC_RMID)) { perror("semctl"); exit(EXIT_FAILURE); } return 0; }