ubuntu 环境共享内存函数shmget与shmat的使用以及shmid:: Invalid argument错误的原因

用于Linux进程通信共享内存。共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。

shmget函数原型

shmget(得到一个共享内存标识符或创建一个共享内存对象)
所需头文件
#include <sys/ipc.h>
#include <sys/shm.h>
函数说明
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
函数原型
int shmget(key_t key, size_t size, int shmflg)
函数传入值
key
0(IPC_PRIVATE):会建立新共享内存对象
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
size
大于0的整数:新建的共享内存大小,以字节为单位
0:只获取共享内存时指定为0
shmflg
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错
函数返回值
成功:返回共享内存的标识符
出错:-1,错误原因存于error中
附加说明
上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限
错误代码
EINVAL:参数size小于SHMMIN或大于SHMMAX
EEXIST:预建立key所指的共享内存,但已经存在
EIDRM:参数key所指的共享内存已经删除
ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL)
ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位
EACCES:没有权限
ENOMEM:核心内存不足
在Linux环境中,对开始申请的共享内存空间进行了初始化,初始值为0x00。
如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:
shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0。
msg_ctime设置为当前时间。
shm_segsz设成创建共享内存的大小。
shmflg的读写权限放在shm_perm.mode中。
shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。

其他共享内存函数

shmat
shmat(把共享内存区对象映射到调用进程的地址空间)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid
共享内存标识符
shmaddr
指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
shmflg
SHM_RDONLY:为只读模式,其他为读写模式
函数返回值
成功:附加好的共享内存地址
出错:-1,错误原因存于error中
附加说明
fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)
错误代码
EACCES:无权限以指定方式连接共享内存
EINVAL:无效的参数shmid或shmaddr
ENOMEM:核心内存不足
shmdt函数原型
shmdt(断开共享内存连接)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
函数原型
int shmdt(const void *shmaddr)
函数传入值
shmaddr:连接的共享内存的起始地址
函数返回值
成功:0
出错:-1,错误原因存于error中
附加说明
本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
错误代码
EINVAL:无效的参数shmaddr
shmctl函数原型

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,却无足够的权限执行

原文地址:

shmget出现shmget:Invalid argument错误—(可能是生成的key值不可用,还有就是key对应的共享内存已经存在,但是要求空间变大出现问题)  

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520108257175568/


/*
注意::    产生问题的原因有下面两种情况,第二种情况已经被确认。
情况一、
         最近在和同事交流的过程中,同事说ftok()并不安全,
         生成的key值并不一定是唯一的。
         有可能申请的key值已经被其他类型的IPC使用,所以,可以自己设计key。
         或者,指定key值。
情况二、
 
          shmget在获取shmid时,如果key已经被占用,此时,如果再使用shmget时,第二个参数,空间大小变大,将出现shmget error: Invalid argument个问题。
          因为在Linux下,共享内存的大小可变,但是只能变小,不能变大。
*/
今天遇到一个非常奇怪的情况::
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(int argc, char *argv[])
{
 key_t key;
 int m_id;
 char *m_addr;
 key = ftok("./a.c",0);
 if( key==-1 )
 {
  perror("ftok:");
  exit(1);
 }
 m_id = shmget(key,4096,IPC_CREAT|0666);
 if(m_id == -1)
 {
  perror("shmget:");
  exit(1);
 }
 m_addr = (char *)shmat(m_id,NULL,0);
 if(m_addr == (char*) -1)
 {
  perror("shmat:");
  exit(1);
 }
 printf("key=%d\tshmid=%d\tshm_addr=%p\n",key,m_id,m_addr);
 return 0;
}
这段代码没有任何问题,可以换成下面就怎么都不行(可能在你的机子上是可以的)
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <error.h>
int main(int argc,char *argv[])
{
      //  key_t key = 0;
    key_t key;
      //  int shmid = 0;
    int shm;
      //  char *addr = NULL;
     char *addr = NULL;
       
  key = ftok("./b.c",0);
        if(key == -1)
        {
                perror("ftok");
                exit(1);
        }
        printf("%d\n",key);
  
  shm = shmget(key,4096,IPC_CREAT|0666);
        if(shm == -1)
        {
                perror("shmget");
                exit(1);
        }
        printf("%d\n",shm);
        addr = (char *)shmat(shm,NULL,0);
        if(addr == (char *)-1)
        {
                perror("shmat::");
                exit(1);
        }
        printf("%p\n",addr);
        return 0;
}
//编译通过了,运行时,就是提示::  
共享内存----shmget出现错误----解决             shmget:   Invalid argument - xychenbaihu@yeah - xychenbaihu@yeah的博客
搞的我非常的郁闷,花了一下午的时间没搞定,最后实在没办法了,将::
key = ftok("./b.c",0);
换成
key=ftok("./b",0);
竟然好了。                                  (怀疑这里可能生成的key值不可用,问题的根源还不是很明白)


你可能感兴趣的:(ubuntu,共享内存,shmget,S)