使用C语言理解共享内存

4

我正在尝试使用C语言设置共享内存。我的代码如下:

key_t key = ftok("SomeString", 1);
static int *sharedval;
int shmid = shmget(key, sizeof(int), S_IRUSR | S_IWUSR); // less permissions
sharedval = (int *) shmat(shmid, NULL, 0);
*sharedval = 0;

然而,当运行最后一行时,我遇到了分段错误。在调试时,我可以打印“sharedval”,并获得一个内存地址,可能是我获取的内存中的位置。因此,我认为我所要做的就是使用*sharedval来评估它,但显然不是这样。我应该如何从共享内存中读取?指点一下方向将是很棒的。谢谢!
$ ./a.out 
ftok: No such file or directory
shmget: No such file or directory
Trying shmget with IPC_CREAT
shmget success
shmat success
Segmentation fault: 11

1
你尝试在代码中添加一些错误处理了吗?shmgetshmat都可能失败。 - Mat
shmget()shmat()的返回值是什么? - chrisaycock
shmget = -1898365432 sharedval = 123854848 - adammenges
4个回答

7

在您的情况下,问题可能是给定键没有关联的内存段。在这种情况下,您需要通过在shmget中传递IPC_CREAT标志来创建内存段。请使用perror检查您的错误消息。您可以尝试以下代码:

    #include <stdio.h> //For perror
    ...

    key_t key = ftok("SomeString", 1);
    if ( 0 > key )
    {
       perror("ftok"); /*Displays the error message*/
       /*Error handling. Return with some error code*/
    }
    else /* This is not needed, just for success message*/
    {
       printf("ftok success\n");
    }

    static int *sharedval;
    int shmid = shmget(key, sizeof(int), S_IRUSR | S_IWUSR | IPC_CREAT);
    if ( 0 > shmid )
    {
        perror("shmget"); /*Displays the error message*/
    }
    else /* This is not needed, just for success message*/
    {
       printf("shmget success\n");
    }

    sharedval = (int *) shmat(shmid, NULL, 0);
    if ( 0 > sharedval )
    {
       perror("shmat"); /*Displays the error message*/
       /*Error handling. Return with some error code*/
    }
    else /* This is not needed, just for success message*/
    {
       printf("shmat success\n");
    }
    *sharedval = 0;
    ...

太棒了,感谢你写下这篇文章。但是我遇到了一个错误。我已经将输出添加到我的帖子中。所以当运行*sharedval = ...时,我仍然会得到“分段错误”。 - adammenges
不需要对 shmget 进行双重调用,您可以始终使用 IPC_CREAT 调用它,它将创建一个新段或使用现有段。 - Hasturkun
1
@InBetween:你需要在perror调用后添加错误处理代码,而不是注释掉它。从输出结果可以看出,在当前目录中不存在名为“SomeString”的文件,这也是ftok错误消息所指出的。 @gby也指出了同样的问题。请在运行此代码的路径中创建一个名为“SomeString”的文件并发布输出结果。您能否提供一些有关环境和编译器的信息?@Hasturkun:感谢您的输入!我会更新代码。 - another.anon.coward

3
问题在于ftok需要一个现有的文件作为参数,该文件可以通过fstat传递,而不是任意字符串。来自man页面的说明:
key_t ftok(const char* pathname, int proj_id)
ftok()函数使用给定路径名所指向的文件(必须是现有且可访问的文件)的标识符...
简易的修复方法是尝试:
int main(int argc, char* argv[])
{
  key_t key = ftok(argv[0], 1);
  ...
}

这也解释了为什么你从ftok得到一个ENOENT(没有这样的文件或目录)错误。

2

在现代程序中进行共享内存的正确方式是使用mmapMAP_SHARED。您可以使用普通文件或使用shm_open创建的命名共享内存对象。


1

如上所述,您的代码缺少错误检查。例如,shmat指示错误的方法是返回-1,当它被显示为指针时,看起来像一个长整数 - 所以这里很可能就是发生了这种情况。

具体而言,请注意ftok()需要在Linux文件系统中获取有效文件的路径,以从文件inode编号派生共享内存ID(它不查看文件内容)。除非您当前目录中有一个名为SomeString的文件,否则此调用将失败。

最后但并非最不重要的是,我强烈建议您使用POSIX共享内存API而不是您正在使用的SySV API。有关详细信息,请参见shm_open(3)(http://linux.die.net/man/3/shm_open)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接