写时复制 (COW) 惯用法的线程安全实现?

2024-01-12

谁能指出我的线程安全实现写时复制 (COW) http://en.wikipedia.org/wiki/Copy-on-write成语?示例代码在这个网站 http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-on-write看起来不错——它是线程安全的吗?

如果有人想知道我将用它做什么:我有一个Foo类有一个std::map<int,double>成员。Foo在我的代码中,对象被频繁复制,但副本很少修改所包含的内容map。我发现与复制整个地图内容相比,COW 的性能提升了 22%Foo复制构造函数,但是当使用多个线程时,我的 COW 实现会崩溃。

UPDATE:

好的,这是代码,根据您的要求,简化为最小的示例:

首先,引用计数图:

class RcMap {                             
 public:
  typedef std::map<int,double> Container;
  typedef Container::const_iterator const_iterator;
  typedef Container::iterator iterator;

  RcMap() : count_(1) {}

  RcMap(const RcMap& other) : count_(1) {
    m_ = other.Get();
  }

  unsigned Count() const { return count_; }
  unsigned IncCount() { return ++count_; }
  unsigned DecCount() {
    if(count_ > 0) --count_;
    return count_;
  }
  void insert(int i, double d) {
    m_.insert(std::make_pair(i,d));
  }
  iterator begin() { return m_.begin(); }
  iterator end() { return m_.end(); }
  const_iterator begin() const { return m_.begin(); }
  const_iterator end() const { return m_.end(); }

 protected:
  const Container& Get() const { return m_; }

 private:
  void operator=(const RcMap&); // disallow

  Container m_;
  unsigned count_;
};

这是班级Foo包含这样一张地图RcMap,使用写时复制机制:

class Foo {
 public:
  Foo() : m_(NULL) {}

  Foo(const Foo& other) : m_(other.m_) {
    if (m_) m_->IncCount();
  }

  Foo& operator= (const Foo& other) {
    RcMap* const old = m_;
    m_ = other.m_;
    if(m_ != 0)
      m_->IncCount();
    if (old != 0 && old->DecCount() == 0) {
      delete old;
    }
    return *this;
  }

  virtual ~Foo() {
    if(m_ != 0 && m_->DecCount() == 0){
      delete m_;
      m_ = 0;
    }
  }

  const RcMap& GetMap() const {
    if(m_ == 0)
      return EmptyStaticRcMap();
    return *m_;
  }

  RcMap& GetMap() {
    if(m_ == 0)
      m_ = new RcMap();
    if (m_->Count() > 1) {
      RcMap* d = new RcMap(*m_);
      m_->DecCount();
      m_ = d;
    }
    assert(m_->Count() == 1);
    return *m_;
  }

  static const RcMap& EmptyStaticRcMap(){
    static const RcMap empty;
    return empty;
  }

 private:
  RcMap* m_;
};

我还无法使用这个最小的示例重现崩溃,但在我的原始代码中,当我使用复制构造函数或赋值运算符时,就会发生崩溃Foo平行的物体。但也许有人可以发现线程安全错误?


COW 本质上是线程安全的,因为原始版本本质上是不可变的,并且只有引发副本的线程才能在创建过程中看到复制的版本。您只需要注意两件事:

  1. 确保在进行复制时原始内容不会被另一个线程删除。不过,这是一个正交问题(例如,您可以使用线程安全的引用计数)。
  2. Make sure all the read operations you perform while copying are thread-safe. This is rarely a problem, but sometimes a read might populate a cache, for instance.
    • 事实上,如果违反了这个假设,那就是读取操作不是线程安全的问题,并且可能会影响更多的代码,而不仅仅是 COW。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

写时复制 (COW) 惯用法的线程安全实现? 的相关文章

  • 自动从 C# 代码进行调试过程并读取寄存器值

    我正在寻找一种方法来读取某个地址的 edx 注册表 就像这个问题中所问的那样 读取eax寄存器 https stackoverflow com questions 16490906 read eax register 虽然我的解决方案需要用
  • Func 方法参数的首选命名约定是什么?

    我承认这个问题是主观的 但我对社区的观点感兴趣 我有一个缓存类 它采用类型的缓存加载器函数Func
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 为什么 POSIX 允许在只读模式下超出现有文件结尾 (fseek) 进行搜索

    为什么寻找文件结尾很有用 为什么 POSIX 让我们像示例中那样在以只读方式打开的文件中进行查找 c http en cppreference com w c io fseek http en cppreference com w c io
  • C# 中可空类型是什么?

    当我们必须使用nullable输入 C net 任何人都可以举例说明 可空类型 何时使用可空类型 https web archive org web http broadcast oreilly com 2010 11 understand
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • c# Asp.NET MVC 使用FileStreamResult下载excel文件

    我需要构建一个方法 它将接收模型 从中构建excel 构建和接收部分完成没有问题 然后使用内存流导出 让用户下载它 不将其保存在服务器上 我是 ASP NET 和 MVC 的新手 所以我找到了指南并将其构建为教程项目 public File
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • 是否有比 lex/flex 更好(更现代)的工具来生成 C++ 分词器?

    我最近将源文件解析添加到现有工具中 该工具从复杂的命令行参数生成输出文件 命令行参数变得如此复杂 以至于我们开始允许它们作为一个文件提供 该文件被解析为一个非常大的命令行 但语法仍然很尴尬 因此我添加了使用更合理的语法解析源文件的功能 我使
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但

随机推荐