1.共享内存被映射进程空间后,存在于进程空间的什么位置?
存在于进程数据段
2.共享内存最大限制是多少?
最大限制0x2000000byte
(1)创建共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值:共享内存标志符
key为输出参数
size应该为1024整数倍,4k对其
shmflg权限标志:需要|IPC对象存取权限(如0600)
IPC_CREAT:如果内核中不存在键值与key相等的共享内存,则新建共享内存;如果存在这样的共享内存,返回此共享内存的标志服
IPC_CREATE | IPC_EXCL:如果内存中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错。
(2)将共享内存映射到自己的内存空间shmat
#include <sys/types.h>
#include <sys/shm.h>
void* shmat(int shmid,const void *shmaddr, int shmflg);
shmaddr:当前进程中的地址位置。(void*)0,系统自动选择地址。
返回值:映射地址的第一个字节
(3)解除映射:shmdt
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
#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);
cmd:
IPC_STAT:得到共享内存状态
IPC_SET:改变共享内存状态
IPC_RMID:删除共享内存
。。。
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_t shm_lpid;
shmatt_t shm_nattch;
...
};
struct ipc_perm {
key_t __key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
unsigned short mode;
unsigned short __seq;
};
(5)ftok
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回key_t键值,-1为失败
pathname:存在并且可以访问
proj_id:0-255
共享内存实现:
defined.h
#ifndef __DEFINED_H_
#define __DEFINED_H_
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SHM_KEY_PATH "/home/flz/keypath" // 共享内存key路径,必须存在
#define SHMEM_SIZE (1024 * 4) // 共享内存大小,1024整数倍
typedef struct mhdr
{
unsigned char from; // 1:client, 2:service
unsigned char op; // 操作类型
unsigned short length; // 数据长度
}mhdr;
void create_file(char* filename);
int create_shmem(); // 创建共享内存
void destroy_shmem(void *addr); // 销毁共享内存
#endif
comom.c
#include "defined.h"
// 创建共享内存
int create_shmem()
{
create_file(SHM_KEY_PATH);
key_t key = ftok(SHM_KEY_PATH, 0);
if(key < 0)
{
printf("ftok() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
return -1;
}
int shmid = shmget(key, SHMEM_SIZE, IPC_CREAT | 0666);
if(shmid < 0)
{
printf("shmget() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
return -1;
}
return shmid;
}
// 销毁共享内存
void destroy_shmem(void *addr)
{
int ret = shmdt(addr);
if(ret < 0)
{
printf("shmdt() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
}
}
// 创建文件
void create_file(char* filename)
{
char* lppos0 = filename;
char* lppos1 = strrchr(filename, '/');
char szDir[256] = { 0 };
memcpy(szDir, filename, lppos1 - lppos0);
printf("mkdir %s\n", szDir);
if(mkdir(szDir, 0771) < 0)
{
printf("mkdir() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
}
printf("creating file:%s\n", filename);
FILE *fp = fopen(filename, "w+");
if(fp == NULL)
{
printf("fopen() failed, errno=%d,errmsg=%s\n", errno, strerror(errno));
}
fclose(fp);
}
client.c
#include "defined.h"
// 读线程
void* readthread(void* param)
{
const void* shmaddr = param; // 共享内存地址
while(1)
{
sleep(1);
mhdr header = { 0 };
memcpy(&header, shmaddr, sizeof(mhdr));
printf("share memory data: from=%d, op=%d, length=%d\n", header.from, header.op, header.length);
if(header.length > 0)
{
char data[SHMEM_SIZE] = { 0 };
memcpy(data, shmaddr + sizeof(mhdr), header.length);
printf("data:\n%s\n", data);
}
}
printf("thread quit.\n");
return NULL;
}
int main()
{
int shmid = create_shmem(); // 创建共享内存
if(shmid < 0)
{
printf("create share memory failed!\n");
return -1;
}
printf("created shmem, id=%d\n", shmid);
// 映射共享内存
void *shmaddr = shmat(shmid, NULL, 0);
if(shmaddr == NULL)
{
printf("create share memory failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
// 从共享内存数据
pthread_t tid = 0;
if(pthread_create(&tid, NULL, readthread, shmaddr) < 0)
{
printf("pthread_create() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
if(pthread_join(tid, NULL) < 0)
{
printf("pthread_join() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
end:
destroy_shmem(shmaddr); // 销毁共享内存
return 0;
}
service.c
#include "defined.h"
#include <stdlib.h>
#include <time.h>
// 写线程
void* write_thread(void *param)
{
printf("running write thread...\n");
srand(time(0));
void* shmaddr = param;
while(1)
{
mhdr header = { 0 };
header.from = 1;
header.op = 0;
header.length = 5 + rand()%256;
char buff[300] = { 0 };
for(int i=0;i<header.length;i++)
{
int num = rand()%30;
char ch = 0;
if(num>=0 && num <= 9)
{
ch = '0' + num;
}
else if(num >= 10 && num<=26)
{
ch = (num - 10) + 'a';
}
else if(num >= 27 && num <= 53)
{
ch = (num - 27) + 'A';
}
buff[i] = ch;
}
buff[header.length] = 0;
memcpy(shmaddr, &header, sizeof(header));
memcpy(shmaddr + sizeof(header), buff, header.length);
sleep(1);
}
return NULL;
}
int main()
{
// 创建共享内存
int shmid = create_shmem();
if(shmid < 0)
{
printf("create share memory faild\n");
return 0;
}
printf("share memory id:%d\n", shmid);
void* shmaddr = shmat(shmid, NULL, 0);
if(shmaddr == NULL)
{
printf("shmat() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
printf("share memory addr:0x%x\n", shmaddr);
pthread_t tid = 0;
// 不断地往共享内存写数据
if(pthread_create(&tid, NULL, write_thread, shmaddr) < 0)
{
printf("pthread_create() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
if(pthread_join(tid, NULL) < 0)
{
printf("pthread_join() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
goto end;
}
end:
// 销毁共享内存
destroy_shmem(shmaddr);
return 0;
}
运行结果:
flz@rt1000-virtual-machine:~/test/shm$ ./service &
[1] 18947
flz@rt1000-virtual-machine:~/test/shm$ mkdir /home/flz
mkdir() failed, errno=17, errmsg=File exists
creating file:/home/flz/keypath
share memory id:6
share memory addr:0x45eac000
running write thread...
flz@rt1000-virtual-machine:~/test/shm$ ./client
mkdir /home/flz
mkdir() failed, errno=17, errmsg=File exists
creating file:/home/flz/keypath
created shmem, id=6
share memory data: from=1, op=0, length=124
data:
bBncg3e382jB5BaB81gAnj3AA3d7dpignck2f45gBg6pegnnaak3ln1ii6hn169gilipifbg1hc8qA167d1lBo180j2np3a5pk0dBclClpC9n07md9dbpfkqqebl
share memory data: from=1, op=0, length=156
data:
lqq4q120nneinn3n1qC21aA8mf46Ap8ad4e26g2Cag9p25i3nhAokg3c2Cblhj10ng2loAcq5el7j22cblB18n62n9nako2525Ajo9fCnCC41ng4ffBf8qhn5a3pq60C3jijCpaeo9jhpAea4chd84B5e20a
share memory data: from=1, op=0, length=7
data:
m13cbe3
share memory data: from=1, op=0, length=114
data:
ohnqB3lqhn0Ca5Ce44kBqmBignmA7pq15kA3fal23mn5jebni1l6ojo249Cbqq518oAf5ih022Bmg9fqbC2AaiCfAkiogfhgae17paCA4Ajc7A8ii2