|
Boost : |
From: Pavel Vasiliev (pavel_at_[hidden])
Date: 2003-02-10 10:46:31
Alexander Terekhov wrote:
[...]
>> Pavel Vasiliev wrote:
>> > The true locking/unlocking, not InterlockedIncrement/Decrement()
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Nah, pthread_refcount_t. ;-)
>> > even if availabe, is necessary to support weak references.
>> > [...]
>>
> It's probably a bit more exciting to take care of all possible races
> without "a true lock" protecting both counters. I'm not sure that the
> true locking is *necessary* to support weak references. Do you have
> an illustration, Pavel?
May be the following code answers the challenge? :-).
The "true lock" is still used to protect deallocating code and to
ensure cache sync before "delete something". But the most frequently
used operations acquire/release now are "mutex-free" for both
counters; they take only a single call to atomic_increment/decrement.
Provided that this example is correct, I don't see necessity to
remove the mutex completely. First, it may be used to ensure cache
sync. Second, lock/unlock are to be implemented by atomic_exchange,
and the mutex data - by one integer variable (lightweight spinlock
mutex). All other possible implementations that I currently expect
require at least one additional flag and atomic operations on it. Not
cheaper than lightweight mutex. Or other solutions exist?
Pavel
-----
// Weak reference control block example. Pseudocode.
// More source code comments in
// http://groups.yahoo.com/group/boost/files/refc/weak_ref_atomicity_example.hpp
// Acquires/releases strong count in weak_ref_control_block.
class strong_ptr;
// Acquires/releases weak count in weak_ref_control_block.
class weak_ref;
// Control block for an allocated object. Stores strong and weak counts.
// Allocated object is destructed when strong count drops to 0.
// Control block by itself is destructed when all strong and weak
// references are lost.
class weak_ref_control_block
{
public:
// Called by existing strong_ptr.
void acquire_strong();
void release_strong();
void acquire_weak_from_strong();
// Called by existing weak_ref.
void acquire_weak();
void release_weak();
bool acquire_strong_from_weak();
private:
void strong_refs_lost();
void weak_refs_lost();
void destruct_allocated(); // "delete p_allocated_obj".
void destruct_self(); // "delete this".
atomic_int_type strong_count;
atomic_int_type weak_count;
mutex mutex_destruct;
T *p_allocated_obj;
};
//---------------------------
void weak_ref_control_block::acquire_strong()
{
atomic_increment(&strong_count);
}
//---------------------------
void weak_ref_control_block::release_strong()
{
if(atomic_decrement(&strong_count) == 0)
strong_refs_lost();
}
//---------------------------
void weak_ref_control_block::acquire_weak()
{
atomic_increment(&weak_count);
}
//---------------------------
void weak_ref_control_block::release_weak()
{
if(atomic_decrement(&weak_count) == 0)
weak_refs_lost();
}
//---------------------------
void weak_ref_control_block::acquire_weak_from_strong()
{
acquire_weak();
}
//---------------------------
bool weak_ref_control_block::acquire_strong_from_weak()
{
scope_lock lock(mutex_destruct);
if(atomic_increment(&strong_count) > 0)
return true;
atomic_set(&strong_count, atomic_int_type_MIN);
return false;
}
//---------------------------
void weak_ref_control_block::strong_refs_lost()
{
{
scope_lock lock(mutex_destruct);
if(atomic_query(&strong_count) != 0)
return;
acquire_weak();
atomic_set(&strong_count, atomic_int_type_MIN);
}
destruct_allocated(); // smp caches are in sync due to mutex above
release_weak(); // fire destruct_self().
}
//---------------------------
void weak_ref_control_block::weak_refs_lost()
{
bool b_destruct = atomic_query(&strong_count) < 0
&& atomic_query(&weak_count) == 0;
if(!b_destruct)
return;
sync_smp_caches(mutex_destruct);
destruct_self();
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk