Thread-safe/Atomic Object wrapper - opinions?


#1

Sometimes you need access, to classes/objects/structs from different threads.
This is a template which wraps a object, and protected it against direct access. If you want to modify the object you have to create a copy of it.
Also this template has handy methods like compareAndSet/swap, which helps you to change data in a consistent way, without locking it during the change process.

I’m not saying this is very CPU/Memory efficient, but it should be safe by design.
What do you think? (How can it be improved/optimized?)

Example (Pseudo-Code)

ThreadSafeObject<MyData> data;

void runThread()
{
   while(false)
   {
      MyData localcopy(data.get());
      MyData copyToCompare(localcopy);

      localCopy.applySomeChanges();

      data.compareAndSetBool(localCopy,copyToCompare);
   } 
}
// Thread Safe Object Wrapper
// The object itself is protected against direct access, its only possible to get a copy
// Only Objects&Classes are supported, which have a assignment operator and a copy constructor

template <class ObjectType> 
class ThreadSafeObject
{
public:
	inline ThreadSafeObject (ObjectType _object) noexcept
		: object (_object)
	{
	
	}

	ObjectType get() noexcept	
	{
		ScopedLock sl(cs);
		return object;				
	}

	void set(const ObjectType& _object) noexcept
	{
		ScopedLock sl(cs);
		object=_object;
	}

	bool compareAndSetBool (const ObjectType& newValue, const ObjectType& valueToCompare) noexcept
	{
		ScopedLock sl(cs);
		if (object == valueToCompare)
		{
			object = newValue;
			return true;
		}
		return false;
	}

	ObjectType compareAndSetValue (const ObjectType& newValue, const ObjectType& valueToCompare) noexcept
	{
		ScopedLock sl(cs);
		ObjectType oldValue = object;
		if (oldValue == valueToCompare)
			object = oldValue;

		return oldValue;
	}


	void swap (const ThreadSafeObject& other) noexcept
	{
		ScopedLock sl1(cs);
		ScopedLock sl2(other.cs);
		ObjectType old = object;
		object = other.object;
		other.object = old;
	}



private:
	CriticalSection cs;
	ObjectType object;
};

#2

It’s a good idea. I have a similar class. A few things:

There’s a lot of locking there. Things like your compare and set, since you compare before setting, might work better with readwritelocks, since then multiple readers could be at work.

Using the ‘compareAndSet’ name is a bit tricky. That generally applies to atomic operations, which strongly implies LockFree. You should probably pick another name.

Bruce


#3

thanks for your opinion!

yes good idea, but I’m little bit sceptical, are ReadWriteLocks as fast as simple Locks (especially on low-latency situations)

yes and no, there must be a locking-like mechanism (but on hardware-level), thats the only way atomic operations can work on multi-processors