您的位置:首页 > 其它

进程通信之共享内存

2017-01-06 21:55 267 查看
1、共享内存

     –共享内存是进程间通信中最简单的方式之一。共享内存在各种进程间通信方式中具有最高的效率。因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。解决这些问题的常用方法是通过使用信号量进行同步。

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


shmread.h

#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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: