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

时间:2014-06-26 17:47:14

标签: c++ static thread-safety stdmap

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

IC.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);
}

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

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

我的问题是:这个帖子安全吗?

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

2 个答案:

答案 0 :(得分:1)

SomeICMap::getInitializedInstance不是线程安全的:某个线程可以访问instance_map而另一个线程正在修改它。这是一个数据竞争,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();
}

答案 1 :(得分:0)

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

一个简单的解决方案是在类中添加一个静态std::mutex,并在函数开头围绕它构造一个unique_lock