共享内存指针分段错误

时间:2018-01-08 07:16:47

标签: c++ shared-memory

嘿我正在尝试在两个进程之间创建一个共享对象。并尝试从每个进程中读取和更改它们。这是我的简单结构。

编辑:我在我的结构中添加了一个构造函数。

struct shared{
    shared(){
        value = 10;
        name = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    }
    int value;
    string name;
};

我在调用fork()之前和之后都试过调用shmat()但是没有任何改变它仍然会给出分段错误。

编辑:并在shmat()之后添加一个检查以查看它是否失败。

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
#include <sys/shm.h>
#include <string.h>

using namespace std;

struct shared{
    shared(){
        value = 10;
        name = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    }
    int value;
    string name;
};

int main(){
    int shm_id = shmget(IPC_PRIVATE,sizeof(shared),0);

    if(shm_id == -1){
        cout<<"shmget() failed "<<endl;
        return -1;
    }
    pid_t pid = fork();
    if(pid == -1){
        cout<<"fork() failed "<<endl;
        return -2;
    }

    shared* sharedPtr = (shared*)shmat(shm_id,0,0);


    if(sharedPtr == 0){
        cout<<"shmat() failed "<<endl;
    }

    cout<<"Setting up the object: "<<endl;
    sharedPtr->value = 5;
    sharedPtr->name = "aaaaaa: ";

    if(pid == 0){       //Child process

        cout<<"Child process: "<<endl;
        sharedPtr->value = 10;
        sharedPtr->name  = "bbbbbbb: ";
        cout<<"Changed the object "<<endl;
        return 0;
    }
    if(pid != 0){ //Parent process
        sleep(1);
        cout<<"Parent process: "<<endl;
        cout<< sharedPtr->name << sharedPtr->value<<endl;

    }

    return 0;
}

但我仍然遇到分段错误。

3 个答案:

答案 0 :(得分:4)

指针(if(sharedPtr == 0){)的有效性检查发生在sharedPtr->value中已经取消引用指针之后。因此,您可能会获得此行为,因为您正在取消引用空指针。点击之后>使用指针。

此外,您不能像这样使用共享内存。您将获得一个静态大小的共享内存指针,表示与未初始化的字符串和int相当的内存,请考虑这一点。你基本上有这个:

int : size -> 4 bytes
empty string : size -> 32 bytes

From here系统相关)。然后,当您执行此(shared*)shmat(shm_id,0,0)和此sharedPtr->name = "aaaaaa: "时,您在此结构中创建的string从未调用其构造函数,因此未正确创建。当你执行operator=时,你试图使用一个在任何地方都不存在的函数,因为你调用它的对象没有被正确构造。如果您使用的是原始共享内存,则需要非常小心如何使用它以及占用的内存大小。您还可以考虑使用内存控制器来帮助您,例如boost::interprocess

答案 1 :(得分:3)

由于共享内存密钥不正确,导致崩溃。

但实际上你有各种严重程度的列表问题:

1)IPC_PRIVATE不合适。你需要像这样使用ftok()

key_t key;
if ((key = ftok("/path/to/existing/file", 'R')) == -1) {
  cerr << "ftok() failed: " << strerror(errno) << "\n";
  return -1;
}

2)此检查应在shmget()致电后立即执行。

if(shm_id == -1){
    cout<<"shmget() failed "<<endl;
    return -1;
}

3)使用strerror(errno)将失败描述作为字符串

4)以下是您的主题https://stackoverflow.com/a/22557543/9187525

的示例

5)shmat()失败时返回-1,因此您的检查不正确。

6)std::string通常不合适,因为它使用的是其他进程看不到的堆。根据您的C ++标准版本和字符串的长度,您将崩溃。有关详细信息,请参阅小字符串优化(SSO)。

7)在创建共享内存段以调用默认ctor之后,您需要调用placement new

8)shmget()已过时,您可能希望将mmap()用于共享内存,如果使用C ++,则可能更好使用相应的boost库。

答案 2 :(得分:0)

您需要在调用shmget

时为新创建的细分设置权限
// read/write permissions ---------------------vvvv
int shm_id = shmget(IPC_PRIVATE,sizeof(shared),0666);

然后,您需要在Shred内存段中实际分配对象。

获得指针后,需要使用placement new创建对象:

new (sharedPtr) shared{}; // allocate the object in the shared memory segment

Working example

请注意,在子进程中更改后,字符串会在父进程中更新,但我认为这与字符串实现本身有关,而不是共享内存管理。 (如果我错了,请纠正我)