在类对象段错误中使用 boost::interprocess,为啥?

Posted

技术标签:

【中文标题】在类对象段错误中使用 boost::interprocess,为啥?【英文标题】:using boost::interprocess in class object segfaults, why?在类对象段错误中使用 boost::interprocess,为什么? 【发布时间】:2016-06-04 14:41:19 【问题描述】:

我试图让一些代码工作,它使用一个类来设置和管理共享内存,并从我的主程序调用该类的一个对象。所有代码都直接在我的 main() 中时有效,但是当我在一个类中设置它并实例化该类的一个对象时,我得到一个段错误。

我不知道为什么或如何解决它?

这里的第一个示例显示了在我的 main() 函数中没有问题的示例:

#include <boost/interprocess/managed_shared_memory.hpp>
using namespace boost::interprocess;

typedef struct teststruct 
    int     testint=9;
;

typedef std::pair<teststruct, int> memsh_teststruct;

int main(int argc, char *argv[])



    printf("inMain0\n");


    struct shm_remove
    
        shm_remove()  shared_memory_object::remove("testShare"); 
        ~shm_remove() shared_memory_object::remove("testShare"); 
     remover;

    //Construct managed shared memory
    managed_shared_memory segment(create_only, "testShare", 65536);


    teststruct myTeststruct;
    memsh_teststruct *inst_teststruct;

    inst_teststruct = segment.construct<memsh_teststruct>
        ("name_myTeststruct") 
        (myTeststruct, 0); 

    printf("construct_ptr: %p \n", &inst_teststruct->first);

    inst_teststruct->first.testint = 1234;

    printf("construct_val: %d\n", inst_teststruct->first.testint);




    int mainInt;

    printf("inMain1\n");

    mainInt = inst_teststruct->first.testint;

    printf("mainInt: %d\n", mainInt);

    printf("inMain2\n");

输出看起来不错,像这样:

construct_ptr: 0x7f0d41834118 
construct_val: 1234
inMain0
inMain1
mainInt: 1234
inMain2

这是设置完全相同的共享内存的第二个示例,但使用了一个类。

#include <boost/interprocess/managed_shared_memory.hpp>
using namespace boost::interprocess;

typedef struct teststruct 
    int     testint=9;
;


typedef std::pair<teststruct, int> memsh_teststruct;

class testclass
    public:
        testclass();
        bool something(int in);

        teststruct myTeststruct;
        memsh_teststruct *inst_teststruct;
;



testclass::testclass() 

    struct shm_remove
    
        shm_remove()  shared_memory_object::remove("testShare"); 
        ~shm_remove() shared_memory_object::remove("testShare"); 
     remover;

    //Construct managed shared memory
    managed_shared_memory segment(create_only, "testShare", 65536);

    inst_teststruct = segment.construct<memsh_teststruct>
        ("name_myTeststruct") 
        (myTeststruct, 0); 

    printf("construct_ptr: %p \n", &inst_teststruct->first);

    inst_teststruct->first.testint = 1234;

    printf("construct_val: %d\n", inst_teststruct->first.testint);




int main(int argc, char *argv[])


    printf("inMain0\n");

    int mainInt;
    testclass testclassObj;

    printf("inMain1\n");

    mainInt = testclassObj.inst_teststruct->first.testint;

    printf("mainInt: %d\n", mainInt);

    printf("inMain2\n");

但是第二个例子有段错误,这是输出:

inMain0
construct_ptr: 0x7fa222d37118 
construct_val: 1234
inMain1
Segmentation fault (core dumped)

... 那么为什么要调用

mainInt = testclassObj.inst_teststruct->first.testint;

从 main() 导致段错误?

我还尝试了一些其他变体,例如在我的类中定义其他函数以与共享内存变量进行交互,并且它也会出现段错误。

如果我不得不猜测发生了什么,我感觉共享内存正在关闭或在我预期之前关闭,可能是在退出 testclass() 构造函数之后。但是,我不知道避免这种情况的正确方法,以便在清理整个 testclassObj 对象时从 main() 返回时关闭共享内存。

另一方面,也许我完全错了?

谢谢, 乙

编辑: EDIT2:最后一次编辑被删除,我的错误无关紧要,由于我在 Sean 的回答中对评论线程做了一些愚蠢的事情。

【问题讨论】:

【参考方案1】:

您的猜测是完全正确的,共享内存在您预期之前就已关闭。

managed_shared_memorytestclass::testclass 中构造,并在构造函数末尾超出范围,关闭共享内存,但留下inst_teststruct 指向共享内存的位置。

只要有指向它的指针,您就必须保留segment。最简单的方法可能是将segment 提升为testclass 的班级成员,如下所示:

class testclass 
public:
    testclass();

    managed_shared_memory segment;
    teststruct myTeststruct;
    memsh_teststruct *inst_teststruct;
;

testclass::testclass()
    : segment(create_only, "testShare", 65536) //< Construct managed shared memory

    struct shm_remove 
        shm_remove()  shared_memory_object::remove("testShare"); 
        ~shm_remove()  shared_memory_object::remove("testShare"); 
     remover;

    inst_teststruct = segment.construct<memsh_teststruct>
        ("name_myTeststruct")
        (myTeststruct, 0);

    printf("construct_ptr: %p \n", &inst_teststruct->first);

    inst_teststruct->first.testint = 1234;

    printf("construct_val: %d\n", inst_teststruct->first.testint);

但是,您必须考虑如何最好地管理共享内存的生命周期,尤其是考虑到将涉及另一个进程。

【讨论】:

谢谢肖恩,还没有测试,但有道理。如果我定义了一个析构函数,有没有办法在析构函数中专门调用移除器?我不完全理解 struct shm_remove 是如何由库处理的,据我所见,它被定义然后未触及,但显然具有一些隐式功能。 回想起来,你的答案真的很明显。我只是错过了段是 managed_shared_memory 类型的变量这一事实。 关于明确调用 remove 的问题的答案在这里 ***.com/questions/18130781/… 嗯。这个想法似乎是正确的,但它不会编译。我不确定您的预期语法是否正确,在我的 constructor() 行之后但在 之前有“:segment(...)”位?我尝试了这两个并将其放入构造函数()此处和 managed_shared_memory 段中;公开:,但是得到我在原始问题中编辑的错误..有什么想法吗? @user1246135 为了简洁起见,这是我将其剥离之前的完整代码。它在 msvc 中对我来说编译得很好。 rextester.com/JJDT38316

以上是关于在类对象段错误中使用 boost::interprocess,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

boost的named_mutex的一些坑

对象在类中的存储方式有哪些?

静态数组仅在类定义内溢出堆栈(段错误 11),否则不会......?

在类中存储对对象的 const 引用

在类库中使用 WCF 服务时出错

在类中创建对象时,不会指定“新”对象