// 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(); //---------------------------------
}