Figure 1: Various thread-safe and thread-unsafe implementations of COW
// Thread-unsafe COW: no locks // void String::EnsureUnique() { if( data_->refs > 1 ) { StringBuf* newdata = new StringBuf( *data_ ); --data_->refs; // now all the real work is data_ = newdata; // done, so take ownership } } // Thread-safe COW: atomic integer operations // // Uses atomic integer calls to serialize access to data_->refs. // Note that the IntAtomic* calls are not necessary function // calls, but can be as efficient as a native assembler // instruction. They still introduce overhead, however, because // EnsureUnique must be called by every possibly-mutating String // function, and the IntAtomic* operations are slower than normal // integer operations. // void String::EnsureUnique() { if( IntAtomicCompare( data_->refs, 1 ) > 0 ) { StringBuf* newdata = new StringBuf( *data_ ); if( IntAtomicDecrement( data_->refs ) < 1 ) { delete newdata; // just in case two threads data_->refs = 1; // are trying this at once } else { // now all the real work is data_ = newdata; // done, so take ownership } } } // Thread-safe COW: critical sections // // Each data_ buffer contains a critical section object for // serializing access to data_->refs. This method is needlessly // inefficient, but it is used in some popular commercial string // libraries. EnsureUnique still is called by every possibly- // mutating String function, but the overhead is worse than with // IntAtomic* functions. // void String::EnsureUnique() { Lock<CriticalSection> l(data_->cs); //--------- if( data_->refs > 1 ) { StringBuf* newdata = new StringBuf( *data_ ); --data_->refs; data_ = newdata; } l.Unlock(); //--------------------------------- }