Multi-threaded tree template data structure



Hi All -
To clarify more about the const_cast<T &>(<volatile object
reference>) - I have attempted to write a thread-safe binary-tree
template ( called as SafeTree<T> ). The following code should
compile.
Can somebody help me with letting me know if this would be race-
free. Also please do let me know if there are possible code syntax
with undefined behavior. Thanks for the help.

#include <iostream>
#include <cstdlib>

using std::cerr;

class Mutex
{
public:
//Fill Here: Apply platform specific thread details for a mutex.
//On linux, use pthreads API
bool lock(bool blocking) volatile
{

return true;
}

bool unlock() volatile
{

return false;
}

//pthread_mutex_t mut;
};

/**
* This template snippet is taken from
* Andrei Alexandrescu's article - to avoid race conditions.
* http://www.ddj.com/cpp/184403766 .
* Any errors in the code would be mine.
**/
template<typename T> class LockingPtr
{
public:
// Constructors/destructors
LockingPtr(volatile T& _obj, volatile Mutex & mtx) :
obj(const_cast<T*>(&_obj)), mutex(&mtx)
{
mtx.lock(true);
}
~LockingPtr()
{
mutex->unlock();
}
// Pointer behavior
T& operator*()
{
return *obj;
}
T* operator->()
{
return obj;
}
private:

LockingPtr<T>(const LockingPtr<T> & rhs)
{
obj = rhs.obj;
mutex = rhs.mutex;
}

LockingPtr<T> & operator=(const LockingPtr<T> & rhs)
{
if (this != &obj)
{
obj = rhs.obj;
mutex = rhs.mutex;
}
return *this;
}

T* obj;
volatile Mutex * mutex;

};

template<typename T> class SafeTree
{
public:
SafeTree<T>(const T & _info) :
info(_info), parentnode(0), leftnode(0), rightnode(0), temp(0)
{
}

SafeTree<T>(const T & _info, volatile SafeTree<T> * _parent) :
info(_info), parentnode(_parent), leftnode(0), rightnode(0),
temp(0)
{
}

virtual ~SafeTree<T>()
{
}

T & getInfo() volatile
{
LockingPtr<T> pObj(info, mutex);
return *pObj;
}

void setInfo(const T & _info) volatile
{
LockingPtr<T> pObj(info, mutex);
*pObj = _info;
}

void freeLeft() volatile
{
LockingPtr<int> pObj(temp, mutex);
if (leftnode)
{
delete leftnode;
leftnode = 0;
}

}

void freeRight() volatile
{
LockingPtr<int> pObj(temp, mutex);

if (rightnode)
{
delete rightnode;
rightnode = 0;
}

}

SafeTree<T> * left() volatile
{
return const_cast< SafeTree<T> *>(leftnode);
}

SafeTree<T> * right() volatile
{
return const_cast< SafeTree<T> *>(rightnode);
}

SafeTree<T> * parent() volatile
{
return const_cast< SafeTree<T> *>(parentnode);
}

SafeTree<T> * sibling() volatile
{
LockingPtr<int> pObj(temp, mutex);

if (parentnode == 0)
{
cerr << "Parent node is null. No Sibling hence";
return 0;
}
else
{
if (parentnode->leftnode == this)
{
return parentnode->right();
}
else
{
return parentnode->left();
}
}
}

bool isLeafNode() volatile
{
LockingPtr<int> pObj(temp, mutex);

return (leftnode == 0) && (rightnode == 0);
}

void insertLeft(const T & data) volatile
{
LockingPtr<int> pObj(temp, mutex);

if (leftnode == 0)
{
SafeTree<T> * newnode = new SafeTree<T>(data, this);
leftnode = newnode;
}

}

void insertRight(const T & data) volatile
{
LockingPtr<int> pObj(temp, mutex);

if (rightnode == 0)
{
SafeTree<T> * newnode = new SafeTree<T>(data, this);
rightnode = newnode;
}
}

void deleteLeft(T & obj) volatile
{
LockingPtr<int> pObj(temp, mutex);

internalDeleteChild(leftnode, obj);
leftnode = 0;
}

void deleteRight(T & obj) volatile
{
LockingPtr<int> pObj(temp, mutex);

internalDeleteChild(rightnode, obj);
rightnode = 0;
}

private:

void internalDeleteChild(SafeTree<T> * child, T & obj)
{
if (child)
{
obj = child->info;
delete child;
}
}

volatile T info;

volatile SafeTree<T> * parentnode;
volatile SafeTree<T> * leftnode;
volatile SafeTree<T> * rightnode;

volatile int temp;

Mutex mutex;
};

int main()
{
SafeTree<int> * root = new SafeTree<int>(4);
root->insertLeft(6);

return EXIT_SUCCESS;
}

.



Relevant Pages

  • Re: Is the following code MT-Safe?
    ... First, you're not protecting any ... This variable will be destroyed and the mutex[*] released when the scope ... >going back to main memory to get the new value which was set by the ... If all access to _bRunning is protected by a mutex, then volatile serves no ...
    (microsoft.public.vc.mfc)
  • Re: Should I use mutex in this context?
    ... My main thread asks the worker thread to terminate if system is ... memory system, the result of the write may be indefinitely delayed from the ... mutex; using a mutex would be the recommended approach. ... or you can cheat and declare the bool volatile. ...
    (microsoft.public.vc.language)
  • Re: Lock-free proxy algorithm
    ... store(type* obj, deleter_t deleter); ... static void acquire(stored_type volatile* ptr); ... explicit scoped_handle(provider const& p); ...
    (comp.programming.threads)
  • Re: shared memory between processes
    ... > compiler to always refer to the actual memory location are neccesary. ... need volatile. ... no mutex and yes, ...
    (comp.os.linux.development.system)
  • Re: MSDN volatile sample
    ... volatile just slows down your code and confounds ... Conversely, if you use volatile instead of a mutex, your code is probably ... depending on the compiler and the machine architecture, ... anything atomic that isn't already atomic, and atomicity is frequently ...
    (microsoft.public.vc.language)

Loading