种族条件:更新结构可以返回一半的旧指针和一半的新指针

发布于 2025-02-12 04:00:34 字数 3677 浏览 4 评论 0原文

void ZMDAggregator::getMZMap(DataModel::MZMap &mZM)
{
    LOGGER_EVENT("ZMDAggregator getMZMap()");
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);    
    mZM.clear();
    mZM = this->mZM;        
}

void ZMDAggregator::Roscallback(const ros::MZMap msgMZMap)
{   
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);
    MZMap map;
    for( auto const & entry : msgMZMap.m_z_e)
    {
        mzEntry.clear();
        mzEntry.mID = entry.mID;
        mzEntry.tMode = entry.tMode;
        mzEntry.areaID = entry.areaID;
        mzEntry.oZone = entry.oZone;        
        mzEntry.authZ = entry.authZ;
        mzEntry.blockZ = entry.blockZ;        
        map.mzEntry.push_back(mzEntry);                        
    }
}

上述功能每秒被调用约30倍。这在我的程序中引起了较高的CPU利用率。

struct MZEntry
{       
    uint32_t mID;
    bool tMode;
    uint32_t areaID;        
    uint32_t oZone;        
    using ZList = std::vector<uint32_t>;
    ZList authZ;        
    ZList blockZ;        
};

struct MZMap
{
    std::vector<MZEntry> mzEntry;
}

Class ZMDAggregator {    
    mutable std::mutex internalStateMutex;
    MZMap mzMap;
}

我的问题是,我是否将getMzmap()转换为接受共享_ptr而不是参考,并且还将成员变量的类型更改为mzmap,如下所示。

void ZMDAggregator::getMZMap(std::shared_ptr<DataModel::MZMap> &mZM)
{
    LOGGER_EVENT("ZMDAggregator getMZMap()");
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);        
    mZM = this->mZM;        
}

Class ZMDAggregator {

    mutable std::mutex internalStateMutex;
    std::shared_ptr<DataModel::MZMap> mzMap;
}

我的问题如下。

我的类zmdaggregator每50毫秒一次更新结构一次,因此每秒大约20倍,您可以看到这发生在unique_lock中。 调用的线程,getMzmap()每秒将其调用约20倍。

通过将初始结构修改为shared_ptr,我应该能够放下CPU周期,因为现在避免了结构副本。但是,现在由于在呼叫者线程中访问了相同的指针(读取器) 当功能roscallback更新结构时,我的风险可能会得到一半旧的指针和一半的新指针。

如果不使用Mutex,(这两个功能是两个单独的类)是否可以确保上述方案不会出现?

根据@freakish的建议,我返回了shared_ptr。请在下面找到代码。

#include <iostream>
#include <memory>
#include <vector>

struct MZEntry
{
    uint32_t mID;
    bool tMode;
    uint32_t areaID;
    uint32_t oZone;
    using ZList = std::vector<uint32_t>;
    ZList authZ;
    ZList blockZ;
};

struct MZMap
{
    std::vector<MZEntry> mzEntry;
};

class A
{
public:
    void populate()
    {
        std::cout << "A populate()" << std::endl;
        MZEntry mzEntry;
        mzEntry.mID = 55;
        mzEntry.tMode = true;
        mzEntry.areaID = 55;
        mzEntry.oZone = 55;
        mzEntry.authZ = {1,2,3};
        mzEntry.blockZ = {4,5,6};
        l->mzEntry.push_back(mzEntry);
    }
    std::shared_ptr<MZMap> assign() const
    {
        return l;
    }
    std::shared_ptr<MZMap> l;

    A()
    {
        std::cout << "A constructor()" << std::endl;
        l = std::make_shared<MZMap>();
        populate();
    }
};

class B
{
public:

    B()
    {
        std::cout << "B constructor" << std::endl;
        a = new A();
    }
    void getValue()
    {
        std::cout << "B getValue()" << std::endl;
        p3 = a->assign();
    }
    void print()
    {
        std::cout << "machineID:  " << p3->mzEntry[0].mID << std::endl;
    }

    std::shared_ptr<MZMap> p3;
    A *a;
};

int main() {

    B *b = new B();

    b->getValue();
    b->print();
    return 0;
}

那么您在行中说的是

    p3 = a->assign();

它不做结构副本,而只是增加了参考计数吗?我的理解正确吗?

void ZMDAggregator::getMZMap(DataModel::MZMap &mZM)
{
    LOGGER_EVENT("ZMDAggregator getMZMap()");
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);    
    mZM.clear();
    mZM = this->mZM;        
}

void ZMDAggregator::Roscallback(const ros::MZMap msgMZMap)
{   
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);
    MZMap map;
    for( auto const & entry : msgMZMap.m_z_e)
    {
        mzEntry.clear();
        mzEntry.mID = entry.mID;
        mzEntry.tMode = entry.tMode;
        mzEntry.areaID = entry.areaID;
        mzEntry.oZone = entry.oZone;        
        mzEntry.authZ = entry.authZ;
        mzEntry.blockZ = entry.blockZ;        
        map.mzEntry.push_back(mzEntry);                        
    }
}

The above function gets called around 30 times a second.This is causing a high cpu utilization in my program.

struct MZEntry
{       
    uint32_t mID;
    bool tMode;
    uint32_t areaID;        
    uint32_t oZone;        
    using ZList = std::vector<uint32_t>;
    ZList authZ;        
    ZList blockZ;        
};

struct MZMap
{
    std::vector<MZEntry> mzEntry;
}

Class ZMDAggregator {    
    mutable std::mutex internalStateMutex;
    MZMap mzMap;
}

My question is if I convert getMZMap() to accept a shared_ptr instead of a reference and also change the type of the member variable mzMap to a shared_ptr as shown below.

void ZMDAggregator::getMZMap(std::shared_ptr<DataModel::MZMap> &mZM)
{
    LOGGER_EVENT("ZMDAggregator getMZMap()");
    std::unique_lock<std::mutex> lockSlot(internalStateMutex);        
    mZM = this->mZM;        
}

Class ZMDAggregator {

    mutable std::mutex internalStateMutex;
    std::shared_ptr<DataModel::MZMap> mzMap;
}

My question is as follows.

My class ZMDAggregator updates the structure once every 50 milliseconds, so around 20 times a second As you can see this happens inside the unique_lock.
The Thread that calls, getMZMap() calls it around 20 times a second.

By modifying initial structure to a shared_ptr, I should be able to bring down CPU cycles, as a struct copy is now avoided. However now since the same pointer is being accessed in the caller thread (Reader)
there is a risk that I can get half an old pointer and half a new pointer when the function Roscallback updates the structure.

Without using a mutex, (These two functions are two separate classes) is there a way to ensure that the above scenario doesn't occour ?

As per the suggestion of @freakish, I have returned shared_ptr by value. Please find the code below.

#include <iostream>
#include <memory>
#include <vector>

struct MZEntry
{
    uint32_t mID;
    bool tMode;
    uint32_t areaID;
    uint32_t oZone;
    using ZList = std::vector<uint32_t>;
    ZList authZ;
    ZList blockZ;
};

struct MZMap
{
    std::vector<MZEntry> mzEntry;
};

class A
{
public:
    void populate()
    {
        std::cout << "A populate()" << std::endl;
        MZEntry mzEntry;
        mzEntry.mID = 55;
        mzEntry.tMode = true;
        mzEntry.areaID = 55;
        mzEntry.oZone = 55;
        mzEntry.authZ = {1,2,3};
        mzEntry.blockZ = {4,5,6};
        l->mzEntry.push_back(mzEntry);
    }
    std::shared_ptr<MZMap> assign() const
    {
        return l;
    }
    std::shared_ptr<MZMap> l;

    A()
    {
        std::cout << "A constructor()" << std::endl;
        l = std::make_shared<MZMap>();
        populate();
    }
};

class B
{
public:

    B()
    {
        std::cout << "B constructor" << std::endl;
        a = new A();
    }
    void getValue()
    {
        std::cout << "B getValue()" << std::endl;
        p3 = a->assign();
    }
    void print()
    {
        std::cout << "machineID:  " << p3->mzEntry[0].mID << std::endl;
    }

    std::shared_ptr<MZMap> p3;
    A *a;
};

int main() {

    B *b = new B();

    b->getValue();
    b->print();
    return 0;
}

So what you are saying is in the line

    p3 = a->assign();

It doesn't do a struct copy, instead it just increments the reference count? Is my understanding correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文