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

标签 c++ static thread-safety stdmap

好的,我已经在万能的谷歌上搜索了一些适合我的问题的明确答案,但我没有成功。我正在用 C++ 开发一个硬件抽象层,它通过各种串行协议(protocol)(SPI、I2C、UART)进行通信,我在板上有很多需要控制的 IC。每个 IC 都有自己的类别。由于我通过类对硬件进行建模,因此我认为在我的代码中拥有与安装在电路板上的 IC 数量相同的实例数量对我来说很重要。 这是我的问题:我需要控制这些实例的创建。我想出的解决方案是将实例存储在一个 static std::map 中,它有一个 std::string 作为键(我使用 SPI 的设备名称,以及 I2C 的地址例子)。代码是这样的:

集成电路.h

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

集成电路.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();
}

这样我就不会得到安装在板上的硬件的重复实例。我为每个 IC 都做了这个。

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

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

最佳答案

SomeICMap::getInitializedInstance 不是线程安全的:某些线程可能会访问 instance_map 而另一个线程正在修改它。这是一场数据竞争,C++ 没有为具有数据竞争的程序定义行为。您可以通过将互斥锁放入类中并确保在持有互斥锁的同时执行对 map 的所有访问来解决此问题:

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();
}

关于C++ 静态函数和线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24437014/

相关文章:

c++ - 模板定义如何与模板声明匹配?

c - 在 "C"头文件中声明的静态函数

java - 有关 Java Servlet 的详细线程安全问题

c++ - Windows 的 Bignum 库?

c++ - 使用三元运算符并删除移动/复制构造函数时,Visual Studio 不执行 RVO

c++ - C++ 中的滴答计数和毫秒

java - 具有静态方法和初始化方法的类的并发

arrays - 在哪里定义与 symfony2 中的实体相关的静态数组?

java - DatatypeConverter 是线程安全的吗?

c++ - 关于 GNU ld 'legacy __sync_synchronize' 警告,我该怎么办?