Click here to Skip to main content
12,354,086 members (68,258 online)
Click here to Skip to main content

Stats

32K views
260 downloads
36 bookmarked
Posted

Thread-safe Smart Pointer

, 14 Jul 2009 CPOL
With this thread-safe smart pointer, you can use an object of any type in a multithreaded environment.
//////////////////////////////////////////////////////////////////////////
//
// Author - Oleg Fedchenko
//
// www.MulticoreWinsoft.com
//
//////////////////////////////////////////////////////////////////////////
#pragma once
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
//////////////////////////////////////////////////////////////////////////
template<typename T>
class CThreadPtr
{
public:
    class CLocker : public boost::noncopyable
    {
    public:
        CLocker(const CThreadPtr& threadPtr)
        :m_threadPtr( threadPtr)
        {
			::WaitForSingleObject( m_threadPtr.m_mutexInternal, INFINITE);
			if (m_threadPtr.m_mutexObj)
				::WaitForSingleObject( m_threadPtr.m_mutexObj, INFINITE);
        }
		~CLocker()
		{
			if (m_threadPtr.m_mutexObj)
				::ReleaseMutex( m_threadPtr.m_mutexObj);
			::ReleaseMutex( m_threadPtr.m_mutexInternal);
		}
        T& operator*() const
        { 
            return *m_threadPtr.m_obj;
        }
        T* operator->() const
        { 
            return &*m_threadPtr.m_obj;
        }
    private:
        const CThreadPtr<T>& m_threadPtr;
    };
public:
    CThreadPtr()       : m_mutexInternal(::CreateMutex(NULL, FALSE, NULL)),
						 m_mutexObj(0),
						 m_obj(){}
    CThreadPtr(T* obj) : m_mutexInternal(::CreateMutex(NULL, FALSE, NULL)),
						 m_mutexObj(::CreateMutex(NULL, FALSE, NULL)),
						 m_obj(obj){}

    CThreadPtr(const CThreadPtr& rh) :	m_mutexInternal(::CreateMutex(NULL, FALSE, NULL)),
										m_mutexObj(0),
										m_obj()
	{
		if (::WaitForSingleObject( rh.m_mutexInternal, INFINITE) == WAIT_OBJECT_0)
		{
			// copy if rh is not destroyed
			if (rh.m_mutexObj)
			{
				::WaitForSingleObject( rh.m_mutexObj, INFINITE);
				if (DuplicateHandle( rh.m_mutexObj, &m_mutexObj))
				{
					m_obj = rh.m_obj;
				}
				::ReleaseMutex( rh.m_mutexObj);
			}
			::ReleaseMutex( rh.m_mutexInternal);
		}
	}

	~CThreadPtr()
	{
		::WaitForSingleObject( m_mutexInternal, INFINITE);
		if (m_mutexObj)
		{
			::WaitForSingleObject( m_mutexObj, INFINITE);
			m_obj.reset();
			::CloseHandle(m_mutexObj);
			m_mutexObj = 0;
		}
		::CloseHandle(m_mutexInternal);
	}

    CThreadPtr& operator=(const CThreadPtr& rh)
	{
		// do not copy myself
		if (&rh == this)
			return *this;
		::WaitForSingleObject( m_mutexInternal, INFINITE);
		// clear my obj
		if (m_mutexObj)
		{
			::WaitForSingleObject( m_mutexObj, INFINITE);
			m_obj.reset();
			::CloseHandle(m_mutexObj);
			m_mutexObj = 0;
		}
		// copy if rh is not destroyed
		if (::WaitForSingleObject( rh.m_mutexInternal, INFINITE) == WAIT_OBJECT_0)
		{
			// copy if not null
			if (rh.m_mutexObj)
			{
				::WaitForSingleObject( rh.m_mutexObj, INFINITE);
				if (DuplicateHandle( rh.m_mutexObj, &m_mutexObj))
				{
					m_obj = rh.m_obj;
				}
				::ReleaseMutex( rh.m_mutexObj);
			}
			::ReleaseMutex( rh.m_mutexInternal);
		}
		::ReleaseMutex( m_mutexInternal);
		return *this;
	}

	CLocker operator->() const
    {
        return *this;
    }

    CLocker operator*() const
    {
        return *this;
    }

    void reset()
    {
		::WaitForSingleObject( m_mutexInternal, INFINITE);
		if (m_mutexObj)
		{
			::WaitForSingleObject( m_mutexObj, INFINITE);
			m_obj.reset();
			::CloseHandle(m_mutexObj);
			m_mutexObj = 0;
		}
		::ReleaseMutex( m_mutexInternal);
    }

    void reset(T* obj)
    {
		::WaitForSingleObject( m_mutexInternal, INFINITE);
		if (m_mutexObj)
			::WaitForSingleObject( m_mutexObj, INFINITE);
        m_obj.reset(obj);
		// new mutex for a new obj
		if (m_mutexObj)
			::CloseHandle(m_mutexObj);
		m_mutexObj = ::CreateMutex(NULL, FALSE, NULL);
		//
		::ReleaseMutex( m_mutexInternal);
    }
    operator bool () const
    {
		CLocker lock(*this);
        return (bool)m_obj;
    }
    bool operator! () const
    {
		CLocker lock(*this);
        return !m_obj;
    }
private:
	static bool DuplicateHandle( HANDLE src, HANDLE* dest)
	{
		HANDLE curProcess = ::GetCurrentProcess();
		return ::DuplicateHandle(
			curProcess,	//HANDLE hSourceProcessHandle,
			src,		//HANDLE hSourceHandle,
			curProcess,	//HANDLE hTargetProcessHandle,
			dest,		//LPHANDLE lpTargetHandle,
			0,						//DWORD dwDesiredAccess, // ignored
			FALSE,					//BOOL bInheritHandle,
			DUPLICATE_SAME_ACCESS	//DWORD dwOptions
			) == TRUE;
	}
private:
	HANDLE m_mutexInternal;
	HANDLE m_mutexObj;
    boost::shared_ptr<T>  m_obj;
};
//////////////////////////////////////////////////////////////////////////

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Oleg Fedchenko
United States United States
Oleg Fedchenko is a professional in the field of multicore optimization and multicore development for Windows.
Please, visit this Web site http://MulticoreWinSoft.com

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.160621.1 | Last Updated 14 Jul 2009
Article Copyright 2008 by Oleg Fedchenko
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid