–共享内存是进程间通信中最简单的方式之一。共享内存在各种进程间通信方式中具有最高的效率。因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。解决这些问题的常用方法是通过使用信号量进行同步。
2、int shmget(key_t key, size_t size, int shmflg)
–shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT)
–shmget得到一个共享内存标识符或创建一个共享内存对象
–key:建立新的共享内存对象
–size:新建立的内存大小(以字节为单位)
–shmflg:标识符
例:
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<stdio.h>
#define BUFSZ 4096
int main(void)
{
int shm_id; /*共享内存标识符*/
shm_id = shmget(IPC_PRIVTE, BUFSZ,0666);
if(shm_id < 0) { /*创建共享内存*/
perror("shmgget");
exit(1);
}
printf("successfully created segment :%d\n",shm_id);
system("ipcs -m"); /*调用ipcs命令查看IPC*/
eixt(0);
}
$gcc create_shm.c -o create_shm$./create_shm
successfully created segment :98305
-------shared Memory segments--------
key shemid owner perms bytes nattch status
0x00000000 0 linux-c 600 393216 2 dest
0x00000000 98305 linux-c 666 4096 0
3、将一个存在的共享内存连接到本进程空间
void *shmat(int shmid, const void *shmaddr, int shmflg)
–shmat(shmid, 0, 0)–返回共享的内存地址,否则返回-1
–shmid:共享内存标识符
–shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
–shmflg SHM_RDONLY:为只读模式,其他为读写模式
addr 和 flag 组合 说明要引入的地址值,通常只有两种用法:
注:如函数成功返回值为实际引入的地址,如失败返回-1。shmat()函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加。
4、对共享内存段操作结束时从进程空间中脱离
#include<sys/shm.h>
int shmdt(void *addr);
参数addr是调用shemat()函数的返回值,如函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,如失败返回-1。
例:
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<stdio.h>
int main(int argc, char *argv[])
{
int shm_id;
char *shm_buf;
if(argc != 2) {
printf("USAGE: atshm <identifier>");
exit(1);
}
shm_id = atoi(argv[1]);
if((shm_buf = shmat(shm_id,0 ,0)) < (char *)0) {
perror("shmat");
exit(1);
}
printf("segment attached at %p\n", shm_buf);
system("ipc -m");
sleep(3);
if((shmdt(shm_buf)) < 0) {
perror("shmdt");
exit(1);
}
printf("segment detached \n");
system("ipcs -m");
exit(0);
}
$ gcc opr_shm.c -o opr_shm
segment attached at oxb7723000
key shemid owner perms bytes nattch status
0x00000000 0 linux-c 600 393216 2 dest
0x00000000 98305 linux-c 666 4096 1
key shemid owner perms bytes nattch status
0x00000000 0 linux-c 600 393216 2 dest
0x00000000 98305 linux-c 666 4096 0
5、int shmctl(int shmid, int cmd, struct shmid_ds *buf)
–shmctl(shmid, IPC_RMID, 0) == -1
–shmid:共享内存标识符
–cmd IPC_RMID:删除这片共享内存
–buf:共享内存管理结构体
cmd的值 意义
IPC_STAT 取shm_id 所指向内存共享段的shm_ds结构,对参数buf指向的结构赋值。
IPC_SET 使用buf指向的结构对,sh_mid段的相关结构赋值,只对以下几个域有作用。
shm_perm.uid shm_perm.gid shm_perm.mode
注意此命令只有具备以下条件的进程才可以请求:
(1)进程的用户ID等于shm_perm.cuid shm_perm.uid
(2)超级用户特权进程。
IPC_RMID 删除shm_id所指向的共享内存段,只有当shmid_ds结构的shm_nattch 域为0时
才会真正执行删除命令,否则不会删除该段。注意此命令的请求规则与IPC_SET命令相同
SHM_LOCK 锁定共享内存段在内存,此命令只能由超级用户请求。
SHM_UNLOCK 对共享内存段解锁,此命令只能由超级用户请求。
例:
shmdata.h
#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_H_HEADER
#define TEXT_SZ 2048
struct shared_use_st
{
//作为一个标志,非0:表示可读,0表示可写
int written;
//记录写入和读取的文本
char text[TEXT_SZ];
};
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include "shmdata.h"
int main(void)
{
int running = 1;//程序是否继续运行的标志
void *shm = NULL;//分配的共享内存的原始首地址
struct shared_use_st *shared;//指向shm
int shmid;//共享内存标识符
//创建共享内存
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\nMemory attached at %p\n", shm);
//设置共享内存
shared = (struct shared_use_st*)shm;
shared->written = 0;
while(running)//读取共享内存中的数据
{
//没有进程向共享内存定数据有数据可读取
if(shared->written != 0)
{
printf("You wrote: %s", shared->text);
sleep(rand() % 3);
//读取完数据,设置written使共享内存段可写
shared->written = 0;
//输入了end,退出循环(程序)
if(strncmp(shared->text, "end", 3) == 0)
running = 0;
}
else//有其他进程在写数据,不能读取数据
sleep(1);
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
//删除共享内存
if(shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
shmwrite.h
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shmdata.h"
int main(void)
{
int running = 1;
void *shm = NULL;
struct shared_use_st *shared = NULL;
char buffer[BUFSIZ + 1];//用于保存输入的文本
int shmid;
//创建共享内存
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %p\n", shm);
//设置共享内存
shared = (struct shared_use_st*)shm;
while(running)//向共享内存中写数据
{
//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本
while(shared->written == 1)
{
sleep(1);
printf("Waiting...\n");
}
//向共享内存中写入数据
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared->text, buffer, TEXT_SZ);
//写完数据,设置written使共享内存段可读
shared->written = 1;
//输入了end,退出循环(程序)
if(strncmp(buffer, "end", 3) == 0)
running = 0;
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
sleep(2);
exit(EXIT_SUCCESS);
}