Opened 19 years ago

Closed 18 years ago

#210 closed Bugs (Invalid)

smart_ptr thread safe exception

Reported by: adasilva Owned by: Peter Dimov
Milestone: Component: smart_ptr
Version: None Severity:
Keywords: Cc:

Description

Hi,

Environment :
WindowsXP
boost 1_30_0
VC++6.0SP5

Context :
I am running tests on lot of allocations/assigns between 
two smart pointers shared by two threads.

Bug :
I receive a "bad_weak_ptr" exception in the method
sp_counted_base::add_ref() :

    void add_ref()
    {
#if defined(BOOST_HAS_THREADS)
        mutex_type::scoped_lock lock(mtx_);
#endif
        if(use_count_ == 0 && weak_count_ != 0) 
boost::throw_exception(boost::bad_weak_ptr());
        ++use_count_;
        ++weak_count_;
    }

Test program is like :
#include "boost/shared_ptr.hpp"

class CTest
{
public:
	CTest( )
	{
	}

	virtual ~CTest( )
	{
	}

	void dump( )
	{
		// do nothing.
	}
};

typedef boost::shared_ptr< CTest > CTestPtr;
CTestPtr ptr1;
CTestPtr ptr2;

// The class AThread is just a little wrapper around
// the "_beginthreadex" function call,
// it allows run/cancel/kill on threaded functions.

void thfn1( AThread *threadwrapper, void * )
{
	// Loop until the "threadwrapper" is cancelled.
	while( !threadwrapper->isCanceled( ) )
	{
		// Dummy work to access
		// concurrently the smart pointers...
		ptr1 = CTestPtr( new CTest );
		ptr1 = CTestPtr( new CTest );
		ptr1 = CTestPtr( new CTest );
		CTestPtr p1( ptr1 );
		CTestPtr p2( ptr2 );
		CTestPtr p3( ptr1 );
		CTestPtr p4( ptr1 );
		ptr1 = CTestPtr( new CTest );
		ptr1 = CTestPtr( new CTest );
		ptr1 = CTestPtr( new CTest );
		ptr1->dump( );
		::Sleep( rand( ) % 10 );
	}
}

void thfn2( AThread *threadwrapper, void * )
{
	// Loop until the "threadwrapper" is cancelled.
	while( !threadwrapper->isCanceled( ) )
	{
		ptr2 = ptr1;
		::Sleep( rand( ) % 5 );
		ptr2 = CTestPtr( new CTest );
		ptr2 = CTestPtr( new CTest );
		ptr2 = CTestPtr( new CTest );
		CTestPtr p1( ptr2 );
		CTestPtr p2( ptr2 );
		CTestPtr p3( ptr2 );
		CTestPtr p4( ptr2 );
		ptr2 = CTestPtr( new CTest );
		ptr2 = CTestPtr( new CTest );
		ptr2 = CTestPtr( new CTest );
		::Sleep( rand( ) % 15 );
		ptr1 = ptr2;
	}
}

int main( int argc, char* argv[ ] )
{
	// You can chage the amount of threads
	// to throw the exception.
	const int nThreads = 12;

	AThread *tab[ nThreads ];

	// Create an array of threads.
	for( int i = 0; i < nThreads; i+=2 )
	{
		tab[ i ] = new AThread( thfn1 );
		tab[ i + 1 ] = new AThread( thfn2 );
	}

	// Start all the threads.
	for( i = 0; i < nThreads; ++i )
	{
		tab[ i ]->run( );
	}

	// Sleep during 5 minutes.
	::Sleep( 300000 );

	// Ask the threads to cancel.
	for( i = 0; i < nThreads; ++i )
	{
		tab[ i ]->cancel( );
		tab[ i ]->join( );
		delete tab[ i ];
	}

	return 0;
}

I can give you a little project to test it.

Change History (2)

comment:1 by Peter Dimov, 19 years ago

Logged In: YES 
user_id=305912

Your threads write to 'ptr1' simultaneously without a lock. 
This is not supported. See

http://www.boost.org/libs/smart_ptr/shared_ptr.htm#ThreadS
afety

comment:2 by Peter Dimov, 18 years ago

Status: assignedclosed
Note: See TracTickets for help on using tickets.