线程安全实现写时拷贝(COW)成语? [英] Thread-safe implementation of the Copy-on-write (COW) idiom?
问题描述
任何人都可以指定我线程安全地实施写时复制(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
对象的复制构造函数或赋值运算符时。
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屋!