进程间通信--共享内存

共享内存是LUNIX 系统中最底层的通信机制,也是最快速的通信机制。

共享内存是由内核出于在多个进程间交换信息目的而留出的一块内存区(段)。

如果段的权限设置恰当,每个要访问段内存的进程都可以把它映射到自己的私有空间中,如果一个进程更新了段中的数据,另外的进程也可以看的到,

一个进程创建的段,其他进程也可以进行读写,每个进程都把它自己对共享内存的映像放入自己的地址空间中。

在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,

系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。

共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。

创建共享内存

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

这个函数成功时返回共享内存的ID,失败时返回-1。

key_t key 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。

                                               如果两个进程没有任何关系,所以就用ftok()算出来一个标识符(或者自己定义一个)使用了。

int size 是这块内存的大小.
int flag 是这块内存的模式(mode)以及权限标识。
模式可取如下值:        
IPC_CREAT 新建(如果已创建则返回目前共享内存的id)
IPC_EXCL   与IPC_CREAT结合使用,如果已创建则则返回错误
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如:    IPC_CREAT | IPC_EXCL | 0640   
例子中的0666为权限标识,4/2/1 分别表示读/写/执行3种权限,第一个0是UID,第一个6(4+2)表示拥有者的权限,第二个4表示同组权限,第3个0表示他人的权限。

关于这个函数,要多说两句。
创建共享内存时,shmflg参数至少需要 IPC_CREAT | 权限标识,如果只有IPC_CREAT 则申请的地址都是k=0xffffffff,不能使用;
获取已创建的共享内存时,shmflg不要用IPC_CREAT(只能用创建共享内存时的权限标识,如0640),否则在某些情况下,比如用ipcrm删除共享内存后,用该函数并用IPC_CREAT参数获取一次共享内存(当然,获取失败),则即使再次创建共享内存也不能成功,此时必须更改key来重建共享内存。

####

int main(void)
{
  int shmid = shmget(IPC_PRIVATE , 1024 , 0666);//0表示UID ,666表示权限 //返回共享内存编号
  if(shmid == -1 )
  {
    printf("error!");
  }
  else
  {
    printf("success!");
  }
  return EXIT_SUCCESS;
}

#######

通过命令ipcs -m 查看共享内存

shimd 共享内存编号

附加共享内存区

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

shmat()将这个内存区映射到本进程的虚拟地址空间。

函数原型:
void    *shmat( int shmid , char *shmaddr , int shmflag );

shmat()是用来允许本进程访问一块共享内存的函数。


int shmid是那块共享内存的ID。

char *shmaddr是共享内存的起始地址,如果shmaddr为0,内核会把共享内存映像到调用进程的地址空间中选定位置;

如果shmaddr不为0,内核会把共享内存映像到shmaddr指定的位置。所以一般把shmaddr设为0。

int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。

0表示读写其它的是读写模式成功时,这个函数返回共享内存的起始地址。失败时返回-1

shmdt()函数删除本进程对这块内存的使用,shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。

函数原型:
int shmdt( char *shmaddr );
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。

 通过ipcs -m 可以查看共享内存id号

int main(int arg , char *argv[])
{
  char *shmbuf;
  int shmid = 0;
  if(arg > 1 )
  {

  shmid = atoi(argv[1]);//通过参数得到共享内存id号


  shmbuf = shmat(shmid , 0 , 0);//返回共享内存的起始地址 // 附加到共享内存


  sleep(60);
  shmdt(shmbuf); //释放进程映射的共享内存空间。
}
return EXIT_SUCCESS;
}

共享内存读写:

int main(int arg , char *argv[])
{
  char *shmbuf;
  int shmid = 0;
  if(arg > 2 )
  {

    shmid = atoi(argv[1]);//得到共享内存id号
    shmbuf = shmat(shmid , 0 , 0);//返回共享内存的起始地址 // 附加到共享内存
    if( 1 == atoi(argv[2]))
    {
      scanf("%s" , shmbuf);
    }
    if( 2 == atoi(argv[2]))
    {
      printf("%s " , shmbuf);
    }
    shmdt(shmbuf);
  }
  return EXIT_SUCCESS;
}

 int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmctl(共享内存管理)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
完成对共享内存的控制
函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函数传入值
shmid
共享内存标识符
cmd
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存
buf
共享内存管理结构体。具体说明参见共享内存内核结构定义部分
函数返回值
成功:0
出错:-1,错误原因存于error中
错误代码
EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为shmid的共享内存已被删除
EINVAL:无效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

shell命令:

ipcrm  shm   shmid  删除共享内存shmid为共享内存id号

原文地址:https://www.cnblogs.com/yuankaituo/p/4344161.html