在多线程程序中控制对字符串对象的访问的最佳方法

时间:2015-01-27 01:37:34

标签: c++ string multithreading mutex atomic

我有一个" config"具有一系列属性的类,#34;镜像"配置设置。在整个代码中共享该类的单个实例(使用boost shared_ptr对象),并且由多个线程(大约100个)读取其属性。

有时,设置可能会发生变化,并且会监视"线程更新对象中的适当属性。

对于integer和bool属性,我使用boost atomic,这样当更新发生并且监视器线程设置该值时,所有读取线程都不会在部分更新状态下读取它。

但是,对于字符串属性,我担心将它们设为原子会显着损害性能。看起来这样做的好方法是让字符串属性实际上是指向字符串的指针,然后当更新发生时,可以构建一个新的字符串对象,然后写入共享对象(字符串指针)只会写入要指向的新字符串对象的地址。所以我假设写入时间远远短于将一个新的字符串值写入共享字符串对象。

但是,这样做意味着我想我想将shared_ptrs用于字符串attribs,这样一旦所有读取线程都使用更新的字符串指针属性,就会自动删除保存前一个值的字符串对象。 / p>

举个例子:

class Config
{
  public:
    boost::atomic<boost::shared_ptr<std::string> > configStr1;

    void updateValueInMonitorThread(std::string newValue)
    {
        boost::shared_ptr<string> newValuePtr;
        newValuePtr = newValue;
        configStr1 = newValuePtr;
    }
};

void threadThatReadsConfig(boost::shared_ptr<Config> theConfig)
{
    std::map<std::string, std::string> thingImWorkingOn;
    thingImWorkingOn[*(theConfig->configStr1.load())] = "some value";
}

那有点矫枉过正吗?有没有更好的方法呢?我真的不喜欢读取线程通过解除引用并调用.load()来访问该值的方式。此外,它甚至是线程安全的,还是这些东西实际上否定了原子和/或shared_ptr类型的安全功能?

我知道我可以使用互斥锁并在&#34; getter&#34;中访问时将其锁定。当监视器线程更新字符串的值时写入锁定它,但我想避免这种情况,因为我试图保持配置类简单并且它会有几十个,可能有数百个这样的字符串属性。

提前感谢任何建议/信息!

2 个答案:

答案 0 :(得分:1)

您已经为每个使用者提供了一个shared_ptr给配置对象。因此,如果配置对象不总是相同的对象,线程将不会注意到。

也就是说,当主配置发生变化时,生成一个全新的配置对象。这似乎是很多复制,但我敢打赌它很少发生,你不会注意到开销。然后你可以将新配置对象替换为旧配置对象,当旧对象的所有使用者完成它时,它将消失。

显然,这会改变配置对象使用的语义。希望能够注意到配置更改的长时间运行的线程必须定期刷新其配置对象。最简单的方法是在每次使用配置数据时获取新的配置对象;再次,这不太可能太昂贵,除非您在硬循环中使用配置字符串。

从好的方面来说,您可以创建整个配置对象const,这可能允许进行一些优化。

答案 1 :(得分:0)

使用互斥变量来设置对共享资源的锁定(这里是你的字符串对象)的经典方法不仅是处理这种情况的最佳但最有效的方法,否则你可能会因为保护不完整而遇到麻烦或者你最终可能会有一个有更多开销的解决方案。在某些应用程序中,您可以通过对单独的对象使用单独的互斥锁来提高效率,以便在对象更新时,其他对象仍可访问。