提升信号量导致段错误

Posted

技术标签:

【中文标题】提升信号量导致段错误【英文标题】:boost semaphore cause segfault 【发布时间】:2016-12-01 15:29:46 【问题描述】:

我想从外部硬件轮询数据并通过信号发送数据。

我的代码导致了段错误,当调用共享内存中的信号量时,我无法弄清楚原因。

下面是我正在做的一个小例子。 基本上启动两个boost线程,一个在共享内存中写入数据,另一个读取数据。

main 只是启动 ThreadHandler ,休眠 并停止 ThreadHandler。

标题:

struct SharedData
    boost::interprocess::interprocess_semaphore sem;
    int data;
    bool newData;
    SharedData():sem(1),newData(false)
;

class ThreadHandler

public:
    ThreadHandler();
    void start();
    void stop();
    boost::thread *m_Thread;
    boost::thread *m_doerThread;
    void doStuff();
    void createSharedMemory();
    void removeSharedMemory();
    SharedData* m_sharedMemory;
;

来源:

void getStuff(int id);


void ThreadHandler::start()
    createSharedMemory();
    m_doerThread = new boost::thread(boost::bind(&ThreadHandler::doStuff,boost::ref(*this)));
    m_Thread = new boost::thread(boost::bind(&getStuff,1));


void ThreadHandler::stop()
    m_Thread->interrupt();
    m_doerThread->interrupt();

    m_Thread->join();
    m_doerThread->join();


void ThreadHandler::createSharedMemory()
    removeSharedMemory();
    try
        boost::interprocess::shared_memory_object sharedObj(boost::interprocess::create_only,SHARED_MEMORY ,boost::interprocess::read_write);
        sharedObj.truncate(sizeof(SharedData));
        boost::interprocess::mapped_region mappedObj(sharedObj,boost::interprocess::read_write);
        SharedData* helper = (SharedData*)mappedObj.get_address();
        m_sharedMemory = new (helper) SharedData;
    catch(boost::interprocess::interprocess_exception &ex)
        std::cout<<ex.what()<<std::endl;
    catch(std::exception &ex)
        std::cout<<ex.what()<<std::endl;
    


void ThreadHandler::removeSharedMemory()
    boost::interprocess::shared_memory_object::remove(SHARED_MEMORY);


void ThreadHandler::doStuff()
    while(1)
        try
            boost::this_thread::yield();
            m_sharedMemory->sem.wait();
            while(!m_sharedMemory->newData)
                m_sharedMemory->sem.post();
                boost::this_thread::interruption_point();
                boost::this_thread::yield();
                m_sharedMemory->sem.wait();
            
            //doStuff
            m_sharedMemory->newData=false;
            m_sharedMemory->sem.post();
        catch(boost::thread_interrupted &interupt)
            break;
        catch(std::exception &ex)
            std::cout<<ex.what()<<std::endl;
        catch(...)
            std::cout<<"exception"<<std::endl;
        
    


void getStuff(int id)
    SharedData* m_sharedMemory;
    try
        boost::interprocess::shared_memory_object sharedObj(boost::interprocess::open_only,SHARED_MEMORY,boost::interprocess::read_write);
        boost::interprocess::mapped_region mappedObj(sharedObj,boost::interprocess::read_write);
        m_sharedMemory = static_cast<SharedData*>(mappedObj.get_address());
    catch(std::exception &ex)
        std::cout<<ex.what()<<std::endl;
    
    while(1)
        try
            //get Data from hardware
            int i =1;
            m_sharedMemory->sem.wait();
            while(m_sharedMemory->newData)
                m_sharedMemory->sem.post();
                boost::this_thread::interruption_point();
                boost::this_thread::yield();
                m_sharedMemory->sem.wait();
            
            memcpy(&(m_sharedMemory->data),&i,sizeof(int));
            m_sharedMemory->newData=true;
            m_sharedMemory->sem.post();

        catch(boost::thread_interrupted& )
            break;
        catch(std::exception &ex)
            std::cout<<ex.what()<<std::endl;
        
    

我已经尝试过具有相同结果的 boost 和 std 互斥锁。 我是否错误地处理了共享/映射内存?

【问题讨论】:

所有指针是怎么回事,而不是释放你动态分配的对象?您是 Java 还是 C# 背景? 我很抱歉,我必须在发布之前也删除它们 【参考方案1】:
try 
    bip::shared_memory_object sharedObj(bip::create_only, SHARED_MEMORY, bip::read_write);
    sharedObj.truncate(sizeof(SharedData));
    bip::mapped_region mappedObj(sharedObj, bip::read_write);
    SharedData *helper = (SharedData *)mappedObj.get_address();
    m_sharedMemory = new (helper) SharedData;
 catch (bip::interprocess_exception &ex) 
    std::cout << ex.what() << std::endl;
 catch (std::exception &ex) 
    std::cout << ex.what() << std::endl;

在这里,您存储一个指向共享对象的指针 (m_sharedMemory),一旦 try 块退出,该共享对象就会超出范围。轰隆隆!

生产者中的同样问题:

SharedData *m_sharedMemory;
try 
    bip::shared_memory_object sharedObj(bip::open_only, SHARED_MEMORY, bip::read_write);
    bip::mapped_region mappedObj(sharedObj, bip::read_write);
    m_sharedMemory = static_cast<SharedData *>(mappedObj.get_address());
 catch (std::exception &ex) 
    std::cout << ex.what() << std::endl;

C++ 具有确定的存储生命周期,并且没有垃圾收集。正如评论员所暗示的那样,只是左右洒new对你没有任何好处。事实上,这会让你的生活变得更糟,因为现在你不得不担心清理和异常安全。

改为使用自动存储持续时间(堆栈、本地、成员),但要确保对象的生命周期足以满足所有使用它的代码。

这是一个固定的演示,似乎可以满足您的需求:

Live On Coliru

#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/thread.hpp>
#include <fstream>

#define SHARED_MEMORY "29939FC9-D56B-43A0-AED3-239B8DD4182B"

namespace bip = boost::interprocess;

struct SharedData 
    bip::interprocess_semaphore sem;
    int data;
    bool newData;
    SharedData() : sem(1), newData(false) 
;

struct ThreadHandler 
    ThreadHandler()  
    void start();
    void stop();
    boost::thread m_producer;
    boost::thread m_consumer;
    void consumer_func();

    void createSharedMemory();
    void removeSharedMemory();

    bip::shared_memory_object m_sharedObj;
    bip::mapped_region m_mappedObj;
    SharedData *m_sharedMemory = nullptr;

    ~ThreadHandler() 
        stop(); 
    
;

void producer_func(int);

void ThreadHandler::start() 
    createSharedMemory();
    m_consumer = boost::thread(&ThreadHandler::consumer_func, this);
    m_producer = boost::thread(&producer_func, 1);


void ThreadHandler::stop() 
    m_producer.interrupt();
    m_consumer.interrupt();

    m_producer.join();
    m_consumer.join();


void ThreadHandler::createSharedMemory() 
    removeSharedMemory();
    try  
        m_sharedObj    = bip::shared_memory_object(bip::create_only, SHARED_MEMORY, bip::read_write);
        m_sharedObj.truncate(sizeof(SharedData));
        m_mappedObj    = bip::mapped_region(m_sharedObj, bip::read_write);
        m_sharedMemory = new (m_mappedObj.get_address()) SharedData;
     catch (bip::interprocess_exception &ex) 
        std::cout << ex.what() << std::endl;
     catch (std::exception &ex) 
        std::cout << ex.what() << std::endl;
    


void ThreadHandler::removeSharedMemory() 
    try 
        m_sharedMemory = nullptr;
        bip::shared_memory_object::remove(SHARED_MEMORY);
     catch(...) 


void ThreadHandler::consumer_func() 
    while (1) 
        try 
            boost::this_thread::yield();
            m_sharedMemory->sem.wait();
            while (!m_sharedMemory->newData) 
                m_sharedMemory->sem.post();
                boost::this_thread::interruption_point();
                boost::this_thread::yield();
                m_sharedMemory->sem.wait();
            
            // doStuff
            std::cout << "." << std::flush;
            m_sharedMemory->newData = false;
            m_sharedMemory->sem.post();
         catch (boost::thread_interrupted &interupt) 
            break;
         catch (std::exception &ex) 
            std::cout << ex.what() << std::endl;
         catch (...) 
            std::cout << "exception" << std::endl;
        
    


void producer_func(int) 
    try 
        bip::shared_memory_object sharedObj(bip::open_only, SHARED_MEMORY, bip::read_write);
        bip::mapped_region mappedObj(sharedObj, bip::read_write);
        auto m_sharedMemory = static_cast<SharedData *>(mappedObj.get_address());

        while (1) 
            try 
                boost::this_thread::sleep_for(boost::chrono::milliseconds(50));
                // get Data from hardware
                int i = 1;
                m_sharedMemory->sem.wait();
                while (m_sharedMemory->newData) 
                    m_sharedMemory->sem.post();
                    boost::this_thread::interruption_point();
                    boost::this_thread::yield();
                    m_sharedMemory->sem.wait();
                
                memcpy(&(m_sharedMemory->data), &i, sizeof(int));
                m_sharedMemory->newData = true;
                m_sharedMemory->sem.post();

             catch (boost::thread_interrupted &) 
                break;
             catch (std::exception &ex) 
                std::cout << ex.what() << std::endl;
            
        
     catch (std::exception &ex) 
        std::cout << ex.what() << std::endl;
    


int main() 
    ThreadHandler th;
    th.start();
    boost::this_thread::sleep_for(boost::chrono::seconds(3));

【讨论】:

添加了清理示例coliru.stacked-crooked.com/a/813cb99c6b5ffaad(Coliru 不支持共享内存,does Wandbox 也不支持) 非常感谢!我有一个(现在)奇怪的想法,即线程将映射内存保持在范围内 - 但线程不必成为提升线程。所以我搞砸了。 @user7236868 完全没问题;只需删除中断点:coliru.stacked-crooked.com/a/0863e2e3aed1773e 在您使用 std::thread 的示例中,线程未完成。我在 SharedData 中添加了一个布尔值,用于打破我的代码中的循环 就像我说的。如果您需要/想要中断点,请使用 Boost Thread。显然,中断点无论如何都不会在进程间工作。

以上是关于提升信号量导致段错误的主要内容,如果未能解决你的问题,请参考以下文章

嵌套的 DirectConnection 信号导致段错误

当连接类型 = Qt.DirectConnection 时,来自线程对象的 PyQt5 信号会导致段错误

NotifyHeader.code 导致段错误

相当于 Windows/MSVC 上的段错误?

linux 段错误

关于Linux下的段错误