Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;静态函数和线程安全_C++_Static_Thread Safety_Stdmap - Fatal编程技术网

C++ C++;静态函数和线程安全

C++ C++;静态函数和线程安全,c++,static,thread-safety,stdmap,C++,Static,Thread Safety,Stdmap,好吧,我已经在万能的谷歌上搜索了一些适合我问题的清晰的安全套,但我没有成功。我正在开发C++中的硬件抽象层,通过各种串行协议(SPI、I2C、UART)进行通信,并且在板上有很多IC需要控制。每个IC都有自己的类。因为我是通过类来建模硬件的,所以我认为代码中的实例数量与板上安装的IC数量相同对我来说很重要。 我的问题是:我需要控制这些实例的创建。我提出的解决方案是将intances存储在一个静态std::map中,该映射以std::string作为键(例如,我使用SPI的设备名和I2C的地址)。

好吧,我已经在万能的谷歌上搜索了一些适合我问题的清晰的安全套,但我没有成功。我正在开发C++中的硬件抽象层,通过各种串行协议(SPI、I2C、UART)进行通信,并且在板上有很多IC需要控制。每个IC都有自己的类。因为我是通过类来建模硬件的,所以我认为代码中的实例数量与板上安装的IC数量相同对我来说很重要。 我的问题是:我需要控制这些实例的创建。我提出的解决方案是将intances存储在一个静态std::map中,该映射以std::string作为键(例如,我使用SPI的设备名和I2C的地址)。代码是这样的:

IC.h

类SomeICMap{
私人:
静态std::map实例\u map;
公众:
静态IC*getInitializedInstance(std::shared_ptr comm,const std::string&addr);
}
IC.cpp

std::map<std::string addr, std::shared_ptr<IC> > instance_map;

IC* SomeICMap::getInitializedInstance(std::shared_ptr<CommInterface> comm, const std::string& addr) {
    std::map<string, std::shared_ptr<IC> >::iterator it;
    it = instance_map.find(addr);

    if (it == instance_map.end()) {

            std::shared_ptr<IC> device(new IC(comm, addr));

            if (device->init() != 0) {
                return NULL;
            }

            instance_map[addr] = device;
            return device.get();
    }

    return it->second.get();
}
std::map实例\u map;
IC*SomeICMap::getInitializedInstance(std::shared_ptr comm,const std::string&addr){
std::map::it迭代器;
it=instance\u map.find(addr);
if(it==instance_map.end()){
std::共享ptr设备(新IC(通信、地址));
如果(设备->初始化()!=0){
返回NULL;
}
实例映射[addr]=设备;
返回设备。get();
}
返回它->秒。获取();
}
这样我就不会得到安装在板上的硬件的重复实例。我为每个IC都做了这个

我的问题是:这个线程安全吗?


我将在Linux下运行的多线程中使用其中一些IC。我不确定这是否安全,因为我正在访问一个静态映射以获取指针并访问硬件。从我在线阅读的内容来看,对硬件的实际访问是安全的,因为内核在使用write()read()操作打开的文件描述符时会考虑并发性。我担心的是当程序第一次创建IC实例时会出现争用条件。

如果您同时从多个线程调用
getInitializedInstance
,那么不,这不是线程安全的。原因是,
map
插入可能与另一个插入或读取交错


一个简单的解决方案是在类中添加一个静态的
std::mutex
,并在函数开始时围绕它构建一个
唯一的锁。

SomeICMap::getInitializedInstance
不是线程安全的:当另一个线程修改它时,一些线程可能访问
实例映射。这是一个数据竞赛,C++没有定义数据竞赛程序的行为。您可以通过向类中抛出互斥体并确保在保持互斥体的同时执行对映射的所有访问来解决此问题:

class SomeICMap {
private:
    static std::map<std::string addr, std::shared_ptr<IC> > instance_map;
    static std::mutex mtx; // <-------
public:
    static IC* getInitializedInstance(std::shared_ptr<CommInterface> comm,
                                      const std::string& addr);
};

std::map<std::string addr, std::shared_ptr<IC> > SomeICMap::instance_map;
std::mutex SomeICMap::mtx; // <-------

IC* SomeICMap::getInitializedInstance(std::shared_ptr<CommInterface> comm,
                                      const std::string& addr) {
    std::lock_guard<std::mutex> lock(mtx); // <-------
    std::map<string, std::shared_ptr<IC> >::iterator it;
    it = instance_map.find(addr);

    if (it == instance_map.end()) {

            std::shared_ptr<IC> device(new IC(comm, addr));

            if (device->init() != 0) {
                return NULL;
            }

            instance_map[addr] = device;
            return device.get();
    }

    return it->second.get();
}
类SomeICMap{
私人:
静态std::map实例\u map;

静态std::mutex mtx;//stl容器不是线程安全的。最好使用读写器锁,因为创建的对象很少。
class SomeICMap {
private:
    static std::map<std::string addr, std::shared_ptr<IC> > instance_map;
    static std::mutex mtx; // <-------
public:
    static IC* getInitializedInstance(std::shared_ptr<CommInterface> comm,
                                      const std::string& addr);
};

std::map<std::string addr, std::shared_ptr<IC> > SomeICMap::instance_map;
std::mutex SomeICMap::mtx; // <-------

IC* SomeICMap::getInitializedInstance(std::shared_ptr<CommInterface> comm,
                                      const std::string& addr) {
    std::lock_guard<std::mutex> lock(mtx); // <-------
    std::map<string, std::shared_ptr<IC> >::iterator it;
    it = instance_map.find(addr);

    if (it == instance_map.end()) {

            std::shared_ptr<IC> device(new IC(comm, addr));

            if (device->init() != 0) {
                return NULL;
            }

            instance_map[addr] = device;
            return device.get();
    }

    return it->second.get();
}