线程安全实现写时拷贝(COW)成语? [英] Thread-safe implementation of the Copy-on-write (COW) idiom?

查看:155
本文介绍了线程安全实现写时拷贝(COW)成语?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以指定我线程安全地实施写时复制(Copy-on-write) COW)成语? 此网站的示例代码看起来不错 - 是它是线程安全的?



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

UPDATE:



好的,这里的代码, ,因为您要求:



首先,参考计数地图:

  class RcMap {
public:
typedef std :: map< int,double>容器;
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

容器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 对象的复制构造函数或赋值运算符时。

code> 解决方案

RcMap 的引用计数需要做原子以便线程安全。在G ++ 4.1中,您可以使用原子内建来实现这一点。


Can anyone point me to a thread-safe implementation of the Copy-on-write (COW) idiom? The sample code on this site looks good -- is it thread-safe?

In case anyone is wondering what I will be using it for: I have a Foo class that has a std::map<int,double> member. Foo objects are copied very frequently in my code, but the copies rarely modify the contained map. I found that COW gives me a 22% performance boost, compared to copying the whole map contents in the Foo copy constructor, but my COW implementation crashes when multiple threads are used.

UPDATE:

Okay, here is the code, reduced to a minimal example, since you asked for it:

First, a reference-counting map:

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_;
};

And here is the class Foo that contains such a map RcMap, using a Copy-on-write mechanism:

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_;
};

I haven't yet been able to reproduce the crash using this minimal example, but in my original code it happens when I use the copy constructor or assignment operator of Foo objects in parallel. But maybe someone can spot the thread-safety bug?

解决方案

RcMap's reference counts need to be made atomic in order to be thread safe. In G++ 4.1, you an use the atomic builtins to implement this.

这篇关于线程安全实现写时拷贝(COW)成语?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆